Ticket #29256: miqro-29256.patch
| File miqro-29256.patch, 13.2 KB (added by , 12 years ago) |
|---|
-
src/wp-includes/formatting.php
30 30 function wptexturize($text, $reset = false) { 31 31 global $wp_cockneyreplace; 32 32 static $static_characters, $static_replacements, $dynamic_characters, $dynamic_replacements, 33 $default_no_texturize_tags, $default_no_texturize_shortcodes, $run_texturize = true; 33 $default_no_texturize_tags, $default_no_texturize_shortcodes, $run_texturize = true, 34 $apos_flag, $apos, $prime, $double_prime, $opening_quote, $closing_quote, $opening_single_quote, $closing_single_quote; 34 35 35 36 // If there's nothing to do, just stop. 36 37 if ( empty( $text ) || false === $run_texturize ) { … … 105 106 $dynamic_replacements = array( 'apos' => array(), 'quote' => array(), 'dash' => array() ); 106 107 $dynamic = array(); 107 108 $spaces = wp_spaces_regexp(); 109 $apos_flag = '<!--wp-apos-->'; // We need a semantic representation that is not identical to a quote. 108 110 109 111 // '99' and '99" are ambiguous among other patterns; assume it's an abbreviated year at the end of a quotation. 110 112 if ( "'" !== $apos || "'" !== $closing_single_quote ) { 111 $dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}\-\]]|>|' . $spaces . ')/' ] = $apos . '$1' . $closing_single_quote;113 $dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_single_quote; 112 114 } 113 115 if ( "'" !== $apos || '"' !== $closing_quote ) { 114 $dynamic[ '/\'(\d\d)"(?=\Z|[.,)}\-\]]|>|' . $spaces . ')/' ] = $apos . '$1' . $closing_quote;116 $dynamic[ '/\'(\d\d)"(?=\Z|[.,)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_quote; 115 117 } 116 118 117 119 // '99 '99s '99's (apostrophe) But never '9 or '99% or '999 or '99.0. 118 120 if ( "'" !== $apos ) { 119 $dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos ;121 $dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos_flag; 120 122 } 121 123 122 124 // Quoted Numbers like '0.42' … … 131 133 132 134 // Apostrophe in a word. No spaces, double apostrophes, or other punctuation. 133 135 if ( "'" !== $apos ) { 134 $dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos ;136 $dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos_flag; 135 137 } 136 138 137 // 9' (prime)138 if ( "'" !== $prime ) {139 $dynamic[ '/(?<=\d)\'/' ] = $prime;140 }141 142 // Single quotes followed by spaces or ending punctuation.143 if ( "'" !== $closing_single_quote ) {144 $dynamic[ '/\'(?=\Z|[.,)}\-\]]|>|' . $spaces . ')/' ] = $closing_single_quote;145 }146 147 139 $dynamic_characters['apos'] = array_keys( $dynamic ); 148 140 $dynamic_replacements['apos'] = array_values( $dynamic ); 149 141 $dynamic = array(); … … 153 145 $dynamic[ '/(?<=\A|' . $spaces . ')"(\d[.,\d]*)"/' ] = $opening_quote . '$1' . $closing_quote; 154 146 } 155 147 156 // 9" (double prime)157 if ( '"' !== $double_prime ) {158 $dynamic[ '/(?<=\d)"/' ] = $double_prime;159 }160 161 148 // Double quote at start, or preceded by (, {, <, [, -, or spaces, and not followed by spaces. 162 149 if ( '"' !== $opening_quote ) { 163 150 $dynamic[ '/(?<=\A|[([{\-]|<|' . $spaces . ')"(?!' . $spaces . ')/' ] = $opening_quote; 164 151 } 165 152 166 // Any remaining double quotes.167 if ( '"' !== $closing_quote ) {168 $dynamic[ '/"/' ] = $closing_quote;169 }170 171 153 $dynamic_characters['quote'] = array_keys( $dynamic ); 172 154 $dynamic_replacements['quote'] = array_values( $dynamic ); 173 155 $dynamic = array(); … … 261 243 262 244 if ( false !== strpos( $curl, "'" ) ) { 263 245 $curl = preg_replace( $dynamic_characters['apos'], $dynamic_replacements['apos'], $curl ); 246 $curl = wptexturize_primes( $curl, "'", $prime, $opening_single_quote, $closing_single_quote ); 247 $curl = str_replace( $apos_flag, $apos, $curl ); 264 248 } 265 249 if ( false !== strpos( $curl, '"' ) ) { 266 250 $curl = preg_replace( $dynamic_characters['quote'], $dynamic_replacements['quote'], $curl ); 251 $curl = wptexturize_primes( $curl, '"', $double_prime, $opening_quote, $closing_quote ); 267 252 } 268 253 if ( false !== strpos( $curl, '-' ) ) { 269 254 $curl = preg_replace( $dynamic_characters['dash'], $dynamic_replacements['dash'], $curl ); … … 285 270 } 286 271 287 272 /** 273 * Implements a logic tree to determine whether or not "7'." represents seven feet, 274 * then converts the special char into either a prime char or a closing quote char. 275 * 276 * @since 4.1.0 277 * 278 * @param string $haystack The plain text to be searched. 279 * @param string $needle The character to search for such as ' or ". 280 * @param string $prime The prime char to use for replacement. 281 * @param string $open_quote The opening quote char. This function requires that opening quote replacement was already accomplished. 282 * @param string $close_quote The closing quote char to use for replacement. 283 * @return string The $haystack value after primes and quotes replacements. 284 */ 285 function wptexturize_primes( $haystack, $needle, $prime, $open_quote, $close_quote ) { 286 287 $spaces = wp_spaces_regexp(); 288 $flag = '<!--wp-prime-or-quote-->'; 289 290 if ( $open_quote == $close_quote ) { 291 // Algorithm assumes some quotes were already translated, replaced, and are not identical to each other. 292 return $haystack; 293 } 294 295 $sentences = explode( $open_quote, $haystack ); 296 297 foreach( $sentences as $key => &$sentence ) { 298 if ( false === strpos( $sentence, $needle ) ) { 299 continue; 300 } elseif ( 0 !== $key && substr_count( $sentence, $close_quote ) === 0 ) { 301 $sentence = preg_replace( "/$needle(?=\\Z|[.,)}\\-\\]]|>|" . $spaces . ")/", $flag, $sentence, -1, $count ); 302 if ( $count > 1) { 303 // This sentence appears to have multiple closing quotes. Attempt Vulcan logic. 304 $sentence = preg_replace( "/(?<!\d)$flag/", $close_quote, $sentence, -1, $count2 ); 305 if ( 0 === $count2 ) { 306 // The closing quote remains ambiguous. Look for a quote that is followed by a period. 307 $count2 = substr_count( $sentence, "$flag." ); 308 if ( $count2 > 0 ) { 309 // Now assume the rightmost quote-period match is the end of the quotation. 310 $pos = strrpos( $sentence, "$flag." ); 311 } else { 312 // When all else fails, make the rightmost candidate a closing quote. 313 // This is most likely to be problematic in the context of bug #18549. 314 $pos = strrpos( $sentence, $flag ); 315 } 316 $sentence = substr_replace( $sentence, $close_quote, $pos, strlen( $flag ) ); 317 } 318 // Use conventional replacement on any remaining primes and quotes. 319 $sentence = preg_replace( "/(?<=\\d)$needle/", $prime, $sentence ); 320 $sentence = preg_replace( "/(?<=\\d)$flag/", $prime, $sentence ); 321 $sentence = str_replace( $flag, $close_quote, $sentence ); 322 } elseif ( 1 == $count ) { 323 // Found only one closing quote candidate, so give it priority over primes. 324 $sentence = str_replace( $flag, $close_quote, $sentence ); 325 $sentence = preg_replace( "/(?<=\\d)$needle/", $prime, $sentence ); 326 } else { 327 // No closing quotes found. Just run primes pattern. 328 $sentence = preg_replace( "/(?<=\\d)$needle/", $prime, $sentence ); 329 } 330 } else { 331 $sentence = preg_replace( "/(?<=\\d)$needle/", $prime, $sentence ); 332 $sentence = preg_replace( "/$needle(?=\\Z|[.,)}\\-\\]]|>|" . $spaces . ")/", $close_quote, $sentence ); 333 } 334 if ( '"' == $needle ) { 335 $sentence = str_replace( '"', $close_quote, $sentence ); 336 } 337 } 338 339 return implode( $open_quote, $sentences ); 340 } 341 342 /** 288 343 * Search for disabled element tags. Push element to stack on tag open and pop 289 344 * on tag close. 290 345 * -
tests/phpunit/tests/formatting/WPTexturize.php
91 91 //$this->assertEquals('Here is “<a href="http://example.com">a test with a link</a>”… and ellipses.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"... and ellipses.')); 92 92 //$this->assertEquals('Here is “a test <a href="http://example.com">with a link</a>”.', wptexturize('Here is "a test <a href="http://example.com">with a link</a>".')); 93 93 //$this->assertEquals('Here is “<a href="http://example.com">a test with a link</a>”and a work stuck to the end.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"and a work stuck to the end.')); 94 //$this->assertEquals('A test with a finishing number, “like 23”.', wptexturize('A test with a finishing number, "like 23".'));95 //$this->assertEquals('A test with a number, “like 62”, is nice to have.', wptexturize('A test with a number, "like 62", is nice to have.'));94 $this->assertEquals('A test with a finishing number, “like 23”.', wptexturize('A test with a finishing number, "like 23".')); 95 $this->assertEquals('A test with a number, “like 62”, is nice to have.', wptexturize('A test with a number, "like 62", is nice to have.')); 96 96 } 97 97 98 98 /** … … 115 115 $this->assertEquals('‘Class of ’99’', wptexturize("'Class of '99'")); 116 116 $this->assertEquals('‘Class of ’99’s’', wptexturize("'Class of '99's'")); 117 117 $this->assertEquals('‘Class of ’99’s’', wptexturize("'Class of '99’s'")); 118 //$this->assertEquals('“Class of 99”', wptexturize("\"Class of 99\""));118 $this->assertEquals('“Class of 99”', wptexturize("\"Class of 99\"")); 119 119 $this->assertEquals('“Class of ’99”', wptexturize("\"Class of '99\"")); 120 120 $this->assertEquals('{“Class of ’99”}', wptexturize("{\"Class of '99\"}")); 121 121 $this->assertEquals(' “Class of ’99” ', wptexturize(" \"Class of '99\" ")); … … 1727 1727 ), 1728 1728 ); 1729 1729 } 1730 1731 /** 1732 * Ensure primes logic is not too greedy at the end of a quotation. 1733 * 1734 * @ticket 29256 1735 * @dataProvider primes_vs_quotes 1736 */ 1737 function test_primes_vs_quotes( $input, $output ) { 1738 return $this->assertEquals( $output, wptexturize( $input ) ); 1739 } 1740 1741 function data_primes_vs_quotes() { 1742 return array( 1743 array( 1744 "George's porch is 99' long.", 1745 "George’s porch is 99′ long.", 1746 ), 1747 array( 1748 'The best year "was that time in 2012" when everyone partied, he said.', 1749 'The best year “was that time in 2012” when everyone partied, he said.', 1750 ), 1751 array( 1752 "I need 4 x 20' = 80' of trim.", // Works only with a space before the = char. 1753 "I need 4 x 20′ = 80′ of trim.", 1754 ), 1755 array( 1756 '"Lorem ipsum dolor sit amet 1234"', 1757 '“Lorem ipsum dolor sit amet 1234”', 1758 ), 1759 array( 1760 "'Etiam eu egestas dui 1234'", 1761 "‘Etiam eu egestas dui 1234’", 1762 ), 1763 array( 1764 'according to our source, "33% of all students scored less than 50" on the test.', 1765 'according to our source, “33% of all students scored less than 50” on the test.', 1766 ), 1767 array( 1768 "The doctor said, 'An average height is between 5' and 6' in study group 7'. He then produced a 6' chart of averages. A man of 7', incredibly, is very possible.", 1769 "The doctor said, ‘An average height is between 5′ and 6′ in study group 7’. He then produced a 6′ chart of averages. A man of 7′, incredibly, is very possible.", 1770 ), 1771 array( 1772 'Pirates have voted on "The Expendables 3" with their clicks -- and it turns out the Sylvester Stallone-starrer hasn\'t been astoundingly popular among digital thieves, relatively speaking. 1773 1774 As of Sunday, 5.12 million people worldwide had pirated "Expendables 3" since a high-quality copy hit torrent-sharing sites July 23, according to piracy-tracking firm Excipio. 1775 1776 That likely contributed to the action movie\'s dismal box-office debut this weekend. But over the same July 23-Aug. 18 time period, the movie was No. 4 in downloads, after "Captain America: The Winter Soldier" (7.31 million), "Divergent" (6.29 million) and "The Amazing Spider-Man 2" (5.88 million). Moreover, that\'s despite "Expendables 3" becoming available more than three weeks prior to the film\'s U.S. theatrical debut. 1777 1778 String with a number followed by a single quote \'Expendables 3\' vestibulum in arcu mi.', 1779 1780 'Pirates have voted on “The Expendables 3” with their clicks — and it turns out the Sylvester Stallone-starrer hasn’t been astoundingly popular among digital thieves, relatively speaking. 1781 1782 As of Sunday, 5.12 million people worldwide had pirated “Expendables 3” since a high-quality copy hit torrent-sharing sites July 23, according to piracy-tracking firm Excipio. 1783 1784 That likely contributed to the action movie’s dismal box-office debut this weekend. But over the same July 23-Aug. 18 time period, the movie was No. 4 in downloads, after “Captain America: The Winter Soldier” (7.31 million), “Divergent” (6.29 million) and “The Amazing Spider-Man 2” (5.88 million). Moreover, that’s despite “Expendables 3” becoming available more than three weeks prior to the film’s U.S. theatrical debut. 1785 1786 String with a number followed by a single quote ‘Expendables 3’ vestibulum in arcu mi.', 1787 ), 1788 ); 1789 } 1730 1790 } 1791 No newline at end of file