Ticket #29256: miqro-29256.3.patch
File miqro-29256.3.patch, 13.3 KB (added by , 10 years ago) |
---|
-
src/wp-includes/formatting.php
30 30 function wptexturize($text, $reset = false) { 31 31 global $wp_cockneyreplace, $shortcode_tags; 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(); … … 263 246 264 247 if ( false !== strpos( $curl, "'" ) ) { 265 248 $curl = preg_replace( $dynamic_characters['apos'], $dynamic_replacements['apos'], $curl ); 249 $curl = wptexturize_primes( $curl, "'", $prime, $opening_single_quote, $closing_single_quote ); 250 $curl = str_replace( $apos_flag, $apos, $curl ); 266 251 } 267 252 if ( false !== strpos( $curl, '"' ) ) { 268 253 $curl = preg_replace( $dynamic_characters['quote'], $dynamic_replacements['quote'], $curl ); 254 $curl = wptexturize_primes( $curl, '"', $double_prime, $opening_quote, $closing_quote ); 269 255 } 270 256 if ( false !== strpos( $curl, '-' ) ) { 271 257 $curl = preg_replace( $dynamic_characters['dash'], $dynamic_replacements['dash'], $curl ); … … 287 273 } 288 274 289 275 /** 276 * Implements a logic tree to determine whether or not "7'." represents seven feet, 277 * then converts the special char into either a prime char or a closing quote char. 278 * 279 * @since 4.1.0 280 * 281 * @param string $haystack The plain text to be searched. 282 * @param string $needle The character to search for such as ' or ". 283 * @param string $prime The prime char to use for replacement. 284 * @param string $open_quote The opening quote char. Opening quote replacement must be accomplished already. 285 * @param string $close_quote The closing quote char to use for replacement. 286 * @return string The $haystack value after primes and quotes replacements. 287 */ 288 function wptexturize_primes( $haystack, $needle, $prime, $open_quote, $close_quote ) { 289 290 $spaces = wp_spaces_regexp(); 291 $flag = '<!--wp-prime-or-quote-->'; 292 $quote_pattern = "/$needle(?=\\Z|[.,)}\\-\\]]|>|" . $spaces . ")/"; 293 $prime_pattern = "/(?<=\\d)$needle/"; 294 $flag_after_digit = "/(?<=\\d)$flag/"; 295 $flag_no_digit = "/(?<!\\d)$flag/"; 296 297 if ( $open_quote == $close_quote ) { 298 // Algorithm assumes some quotes were already translated, replaced, and are not identical. 299 return $haystack; 300 } 301 302 $sentences = explode( $open_quote, $haystack ); 303 304 foreach( $sentences as $key => &$sentence ) { 305 if ( false === strpos( $sentence, $needle ) ) { 306 continue; 307 } elseif ( 0 !== $key && substr_count( $sentence, $close_quote ) === 0 ) { 308 $sentence = preg_replace( $quote_pattern, $flag, $sentence, -1, $count ); 309 if ( $count > 1) { 310 // This sentence appears to have multiple closing quotes. Attempt Vulcan logic. 311 $sentence = preg_replace( $flag_no_digit, $close_quote, $sentence, -1, $count2 ); 312 if ( 0 === $count2 ) { 313 // Closing quote still ambiguous. Look for a quote followed by a period. 314 $count2 = substr_count( $sentence, "$flag." ); 315 if ( $count2 > 0 ) { 316 // Assume the rightmost quote-period match is the end of quotation. 317 $pos = strrpos( $sentence, "$flag." ); 318 } else { 319 // When all else fails, make the rightmost candidate a closing quote. 320 // This is most likely to be problematic in the context of bug #18549. 321 $pos = strrpos( $sentence, $flag ); 322 } 323 $sentence = substr_replace( $sentence, $close_quote, $pos, strlen( $flag ) ); 324 } 325 // Use conventional replacement on any remaining primes and quotes. 326 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 327 $sentence = preg_replace( $flag_after_digit, $prime, $sentence ); 328 $sentence = str_replace( $flag, $close_quote, $sentence ); 329 } elseif ( 1 == $count ) { 330 // Found only one closing quote candidate, so give it priority over primes. 331 $sentence = str_replace( $flag, $close_quote, $sentence ); 332 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 333 } else { 334 // No closing quotes found. Just run primes pattern. 335 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 336 } 337 } else { 338 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 339 $sentence = preg_replace( $quote_pattern, $close_quote, $sentence ); 340 } 341 if ( '"' == $needle ) { 342 $sentence = str_replace( '"', $close_quote, $sentence ); 343 } 344 } 345 346 return implode( $open_quote, $sentences ); 347 } 348 349 /** 290 350 * Search for disabled element tags. Push element to stack on tag open and pop 291 351 * on tag close. 292 352 * -
tests/phpunit/tests/formatting/WPTexturize.php
90 90 //$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.')); 91 91 //$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>".')); 92 92 //$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.')); 93 //$this->assertEquals('A test with a finishing number, “like 23”.', wptexturize('A test with a finishing number, "like 23".'));94 //$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.'));93 $this->assertEquals('A test with a finishing number, “like 23”.', wptexturize('A test with a finishing number, "like 23".')); 94 $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.')); 95 95 } 96 96 97 97 /** … … 114 114 $this->assertEquals('‘Class of ’99’', wptexturize("'Class of '99'")); 115 115 $this->assertEquals('‘Class of ’99’s’', wptexturize("'Class of '99's'")); 116 116 $this->assertEquals('‘Class of ’99’s’', wptexturize("'Class of '99’s'")); 117 //$this->assertEquals('“Class of 99”', wptexturize("\"Class of 99\""));117 $this->assertEquals('“Class of 99”', wptexturize("\"Class of 99\"")); 118 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\" ")); … … 1771 1771 ), 1772 1772 ); 1773 1773 } 1774 1775 /** 1776 * Ensure primes logic is not too greedy at the end of a quotation. 1777 * 1778 * @ticket 29256 1779 * @dataProvider primes_vs_quotes 1780 */ 1781 function test_primes_vs_quotes( $input, $output ) { 1782 return $this->assertEquals( $output, wptexturize( $input ) ); 1783 } 1784 1785 function data_primes_vs_quotes() { 1786 return array( 1787 array( 1788 "George's porch is 99' long.", 1789 "George’s porch is 99′ long.", 1790 ), 1791 array( 1792 'The best year "was that time in 2012" when everyone partied, he said.', 1793 'The best year “was that time in 2012” when everyone partied, he said.', 1794 ), 1795 array( 1796 "I need 4 x 20' = 80' of trim.", // Works only with a space before the = char. 1797 "I need 4 x 20′ = 80′ of trim.", 1798 ), 1799 array( 1800 '"Lorem ipsum dolor sit amet 1234"', 1801 '“Lorem ipsum dolor sit amet 1234”', 1802 ), 1803 array( 1804 "'Etiam eu egestas dui 1234'", 1805 "‘Etiam eu egestas dui 1234’", 1806 ), 1807 array( 1808 'according to our source, "33% of all students scored less than 50" on the test.', 1809 'according to our source, “33% of all students scored less than 50” on the test.', 1810 ), 1811 array( 1812 "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.", 1813 "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.", 1814 ), 1815 array( 1816 '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. 1817 1818 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. 1819 1820 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. 1821 1822 String with a number followed by a single quote \'Expendables 3\' vestibulum in arcu mi.', 1823 1824 '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. 1825 1826 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. 1827 1828 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. 1829 1830 String with a number followed by a single quote ‘Expendables 3’ vestibulum in arcu mi.', 1831 ), 1832 ); 1833 } 1774 1834 } 1835 No newline at end of file