Ticket #29256: miqro-29256.2.patch
| File miqro-29256.2.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, 35 $closing_single_quote; 34 36 35 37 // If there's nothing to do, just stop. 36 38 if ( empty( $text ) || false === $run_texturize ) { … … 105 107 $dynamic_replacements = array( 'apos' => array(), 'quote' => array(), 'dash' => array() ); 106 108 $dynamic = array(); 107 109 $spaces = wp_spaces_regexp(); 110 $apos_flag = '<!--wp-apos-->'; // We need a semantic representation that is not identical to a quote. 108 111 109 112 // '99' and '99" are ambiguous among other patterns; assume it's an abbreviated year at the end of a quotation. 110 113 if ( "'" !== $apos || "'" !== $closing_single_quote ) { 111 $dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}\-\]]|>|' . $spaces . ')/' ] = $apos . '$1' . $closing_single_quote;114 $dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_single_quote; 112 115 } 113 116 if ( "'" !== $apos || '"' !== $closing_quote ) { 114 $dynamic[ '/\'(\d\d)"(?=\Z|[.,)}\-\]]|>|' . $spaces . ')/' ] = $apos . '$1' . $closing_quote;117 $dynamic[ '/\'(\d\d)"(?=\Z|[.,)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_quote; 115 118 } 116 119 117 120 // '99 '99s '99's (apostrophe) But never '9 or '99% or '999 or '99.0. 118 121 if ( "'" !== $apos ) { 119 $dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos ;122 $dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos_flag; 120 123 } 121 124 122 125 // Quoted Numbers like '0.42' … … 131 134 132 135 // Apostrophe in a word. No spaces, double apostrophes, or other punctuation. 133 136 if ( "'" !== $apos ) { 134 $dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos ;137 $dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos_flag; 135 138 } 136 139 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 140 $dynamic_characters['apos'] = array_keys( $dynamic ); 148 141 $dynamic_replacements['apos'] = array_values( $dynamic ); 149 142 $dynamic = array(); … … 153 146 $dynamic[ '/(?<=\A|' . $spaces . ')"(\d[.,\d]*)"/' ] = $opening_quote . '$1' . $closing_quote; 154 147 } 155 148 156 // 9" (double prime)157 if ( '"' !== $double_prime ) {158 $dynamic[ '/(?<=\d)"/' ] = $double_prime;159 }160 161 149 // Double quote at start, or preceded by (, {, <, [, -, or spaces, and not followed by spaces. 162 150 if ( '"' !== $opening_quote ) { 163 151 $dynamic[ '/(?<=\A|[([{\-]|<|' . $spaces . ')"(?!' . $spaces . ')/' ] = $opening_quote; 164 152 } 165 153 166 // Any remaining double quotes.167 if ( '"' !== $closing_quote ) {168 $dynamic[ '/"/' ] = $closing_quote;169 }170 171 154 $dynamic_characters['quote'] = array_keys( $dynamic ); 172 155 $dynamic_replacements['quote'] = array_values( $dynamic ); 173 156 $dynamic = array(); … … 261 244 262 245 if ( false !== strpos( $curl, "'" ) ) { 263 246 $curl = preg_replace( $dynamic_characters['apos'], $dynamic_replacements['apos'], $curl ); 247 $curl = wptexturize_primes( $curl, "'", $prime, $opening_single_quote, $closing_single_quote ); 248 $curl = str_replace( $apos_flag, $apos, $curl ); 264 249 } 265 250 if ( false !== strpos( $curl, '"' ) ) { 266 251 $curl = preg_replace( $dynamic_characters['quote'], $dynamic_replacements['quote'], $curl ); 252 $curl = wptexturize_primes( $curl, '"', $double_prime, $opening_quote, $closing_quote ); 267 253 } 268 254 if ( false !== strpos( $curl, '-' ) ) { 269 255 $curl = preg_replace( $dynamic_characters['dash'], $dynamic_replacements['dash'], $curl ); … … 285 271 } 286 272 287 273 /** 274 * Implements a logic tree to determine whether or not "7'." represents seven feet, 275 * then converts the special char into either a prime char or a closing quote char. 276 * 277 * @since 4.1.0 278 * 279 * @param string $haystack The plain text to be searched. 280 * @param string $needle The character to search for such as ' or ". 281 * @param string $prime The prime char to use for replacement. 282 * @param string $open_quote The opening quote char. Opening quote replacement must be accomplished already. 283 * @param string $close_quote The closing quote char to use for replacement. 284 * @return string The $haystack value after primes and quotes replacements. 285 */ 286 function wptexturize_primes( $haystack, $needle, $prime, $open_quote, $close_quote ) { 287 288 $spaces = wp_spaces_regexp(); 289 $flag = '<!--wp-prime-or-quote-->'; 290 $quote_pattern = "/$needle(?=\\Z|[.,)}\\-\\]]|>|" . $spaces . ")/"; 291 $prime_pattern = "/(?<=\\d)$needle/"; 292 $flag_after_digit = "/(?<=\\d)$flag/"; 293 $flag_no_digit = "/(?<!\\d)$flag/"; 294 295 if ( $open_quote == $close_quote ) { 296 // Algorithm assumes some quotes were already translated, replaced, and are not identical. 297 return $haystack; 298 } 299 300 $sentences = explode( $open_quote, $haystack ); 301 302 foreach( $sentences as $key => &$sentence ) { 303 if ( false === strpos( $sentence, $needle ) ) { 304 continue; 305 } elseif ( 0 !== $key && substr_count( $sentence, $close_quote ) === 0 ) { 306 $sentence = preg_replace( $quote_pattern, $flag, $sentence, -1, $count ); 307 if ( $count > 1) { 308 // This sentence appears to have multiple closing quotes. Attempt Vulcan logic. 309 $sentence = preg_replace( $flag_no_digit, $close_quote, $sentence, -1, $count2 ); 310 if ( 0 === $count2 ) { 311 // Closing quote still ambiguous. Look for a quote followed by a period. 312 $count2 = substr_count( $sentence, "$flag." ); 313 if ( $count2 > 0 ) { 314 // Assume the rightmost quote-period match is the end of quotation. 315 $pos = strrpos( $sentence, "$flag." ); 316 } else { 317 // When all else fails, make the rightmost candidate a closing quote. 318 // This is most likely to be problematic in the context of bug #18549. 319 $pos = strrpos( $sentence, $flag ); 320 } 321 $sentence = substr_replace( $sentence, $close_quote, $pos, strlen( $flag ) ); 322 } 323 // Use conventional replacement on any remaining primes and quotes. 324 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 325 $sentence = preg_replace( $flag_after_digit, $prime, $sentence ); 326 $sentence = str_replace( $flag, $close_quote, $sentence ); 327 } elseif ( 1 == $count ) { 328 // Found only one closing quote candidate, so give it priority over primes. 329 $sentence = str_replace( $flag, $close_quote, $sentence ); 330 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 331 } else { 332 // No closing quotes found. Just run primes pattern. 333 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 334 } 335 } else { 336 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 337 $sentence = preg_replace( $quote_pattern, $close_quote, $sentence ); 338 } 339 if ( '"' == $needle ) { 340 $sentence = str_replace( '"', $close_quote, $sentence ); 341 } 342 } 343 344 return implode( $open_quote, $sentences ); 345 } 346 347 /** 288 348 * Search for disabled element tags. Push element to stack on tag open and pop 289 349 * on tag close. 290 350 * -
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