Make WordPress Core

Ticket #29256: miqro-29256.3.patch

File miqro-29256.3.patch, 13.3 KB (added by miqrogroove, 11 years ago)

Refreshed

  • src/wp-includes/formatting.php

     
    3030function wptexturize($text, $reset = false) {
    3131        global $wp_cockneyreplace, $shortcode_tags;
    3232        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;
    3436
    3537        // If there's nothing to do, just stop.
    3638        if ( empty( $text ) || false === $run_texturize ) {
     
    105107                $dynamic_replacements = array( 'apos' => array(), 'quote' => array(), 'dash' => array() );
    106108                $dynamic = array();
    107109                $spaces = wp_spaces_regexp();
     110                $apos_flag = '<!--wp-apos-->';  // We need a semantic representation that is not identical to a quote.
    108111
    109112                // '99' and '99" are ambiguous among other patterns; assume it's an abbreviated year at the end of a quotation.
    110113                if ( "'" !== $apos || "'" !== $closing_single_quote ) {
    111                         $dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos . '$1' . $closing_single_quote;
     114                        $dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_single_quote;
    112115                }
    113116                if ( "'" !== $apos || '"' !== $closing_quote ) {
    114                         $dynamic[ '/\'(\d\d)"(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos . '$1' . $closing_quote;
     117                        $dynamic[ '/\'(\d\d)"(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_quote;
    115118                }
    116119
    117120                // '99 '99s '99's (apostrophe)  But never '9 or '99% or '999 or '99.0.
    118121                if ( "'" !== $apos ) {
    119                         $dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos;
     122                        $dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos_flag;
    120123                }
    121124
    122125                // Quoted Numbers like '0.42'
     
    131134
    132135                // Apostrophe in a word.  No spaces, double apostrophes, or other punctuation.
    133136                if ( "'" !== $apos ) {
    134                         $dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos;
     137                        $dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos_flag;
    135138                }
    136139
    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|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $closing_single_quote;
    145                 }
    146 
    147140                $dynamic_characters['apos'] = array_keys( $dynamic );
    148141                $dynamic_replacements['apos'] = array_values( $dynamic );
    149142                $dynamic = array();
     
    153146                        $dynamic[ '/(?<=\A|' . $spaces . ')"(\d[.,\d]*)"/' ] = $opening_quote . '$1' . $closing_quote;
    154147                }
    155148
    156                 // 9" (double prime)
    157                 if ( '"' !== $double_prime ) {
    158                         $dynamic[ '/(?<=\d)"/' ] = $double_prime;
    159                 }
    160 
    161149                // Double quote at start, or preceded by (, {, <, [, -, or spaces, and not followed by spaces.
    162150                if ( '"' !== $opening_quote ) {
    163151                        $dynamic[ '/(?<=\A|[([{\-]|&lt;|' . $spaces . ')"(?!' . $spaces . ')/' ] = $opening_quote;
    164152                }
    165153
    166                 // Any remaining double quotes.
    167                 if ( '"' !== $closing_quote ) {
    168                         $dynamic[ '/"/' ] = $closing_quote;
    169                 }
    170 
    171154                $dynamic_characters['quote'] = array_keys( $dynamic );
    172155                $dynamic_replacements['quote'] = array_values( $dynamic );
    173156                $dynamic = array();
     
    263246
    264247                        if ( false !== strpos( $curl, "'" ) ) {
    265248                                $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 );
    266251                        }
    267252                        if ( false !== strpos( $curl, '"' ) ) {
    268253                                $curl = preg_replace( $dynamic_characters['quote'], $dynamic_replacements['quote'], $curl );
     254                                $curl = wptexturize_primes( $curl, '"', $double_prime, $opening_quote, $closing_quote );
    269255                        }
    270256                        if ( false !== strpos( $curl, '-' ) ) {
    271257                                $curl = preg_replace( $dynamic_characters['dash'], $dynamic_replacements['dash'], $curl );
     
    287273}
    288274
    289275/**
     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 */
     288function 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|[.,)}\\-\\]]|&gt;|" . $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/**
    290350 * Search for disabled element tags. Push element to stack on tag open and pop
    291351 * on tag close.
    292352 *
  • tests/phpunit/tests/formatting/WPTexturize.php

     
    9090                //$this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;&#8230; and ellipses.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"... and ellipses.'));
    9191                //$this->assertEquals('Here is &#8220;a test <a href="http://example.com">with a link</a>&#8221;.', wptexturize('Here is "a test <a href="http://example.com">with a link</a>".'));
    9292                //$this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;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, &#8220;like 23&#8221;.', wptexturize('A test with a finishing number, "like 23".'));
    94                 //$this->assertEquals('A test with a number, &#8220;like 62&#8221;, 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, &#8220;like 23&#8221;.', wptexturize('A test with a finishing number, "like 23".'));
     94                $this->assertEquals('A test with a number, &#8220;like 62&#8221;, is nice to have.', wptexturize('A test with a number, "like 62", is nice to have.'));
    9595        }
    9696
    9797        /**
     
    114114                $this->assertEquals('&#8216;Class of &#8217;99&#8217;', wptexturize("'Class of '99'"));
    115115                $this->assertEquals('&#8216;Class of &#8217;99&#8217;s&#8217;', wptexturize("'Class of '99's'"));
    116116                $this->assertEquals('&#8216;Class of &#8217;99&#8217;s&#8217;', wptexturize("'Class of '99&#8217;s'"));
    117                 //$this->assertEquals('&#8220;Class of 99&#8221;', wptexturize("\"Class of 99\""));
     117                $this->assertEquals('&#8220;Class of 99&#8221;', wptexturize("\"Class of 99\""));
    118118                $this->assertEquals('&#8220;Class of &#8217;99&#8221;', wptexturize("\"Class of '99\""));
    119119                $this->assertEquals('{&#8220;Class of &#8217;99&#8221;}', wptexturize("{\"Class of '99\"}"));
    120120                $this->assertEquals(' &#8220;Class of &#8217;99&#8221; ', wptexturize(" \"Class of '99\" "));
     
    17711771                        ),
    17721772                );
    17731773        }
     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&#8217;s porch is 99&#8242; long.",
     1790                        ),
     1791                        array(
     1792                                'The best year "was that time in 2012" when everyone partied, he said.',
     1793                                'The best year &#8220;was that time in 2012&#8221; 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&#8242; = 80&#8242; of trim.",
     1798                        ),
     1799                        array(
     1800                                '"Lorem ipsum dolor sit amet 1234"',
     1801                                '&#8220;Lorem ipsum dolor sit amet 1234&#8221;',
     1802                        ),
     1803                        array(
     1804                                "'Etiam eu egestas dui 1234'",
     1805                                "&#8216;Etiam eu egestas dui 1234&#8217;",
     1806                        ),
     1807                        array(
     1808                                'according to our source, "33% of all students scored less than 50" on the test.',
     1809                                'according to our source, &#8220;33% of all students scored less than 50&#8221; 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, &#8216;An average height is between 5&#8242; and 6&#8242; in study group 7&#8217;.  He then produced a 6&#8242; chart of averages.  A man of 7&#8242;, 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
     1818As 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
     1820That 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
     1822String with a number followed by a single quote \'Expendables 3\' vestibulum in arcu mi.',
     1823
     1824                                'Pirates have voted on &#8220;The Expendables 3&#8221; with their clicks &#8212; and it turns out the Sylvester Stallone-starrer hasn&#8217;t been astoundingly popular among digital thieves, relatively speaking.
     1825
     1826As of Sunday, 5.12 million people worldwide had pirated &#8220;Expendables 3&#8221; since a high-quality copy hit torrent-sharing sites July 23, according to piracy-tracking firm Excipio.
     1827
     1828That likely contributed to the action movie&#8217;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 &#8220;Captain America: The Winter Soldier&#8221; (7.31 million), &#8220;Divergent&#8221; (6.29 million) and &#8220;The Amazing Spider-Man 2&#8221; (5.88 million). Moreover, that&#8217;s despite &#8220;Expendables 3&#8221; becoming available more than three weeks prior to the film&#8217;s U.S. theatrical debut.
     1829
     1830String with a number followed by a single quote &#8216;Expendables 3&#8217; vestibulum in arcu mi.',
     1831                        ),
     1832                );
     1833        }
    17741834}
     1835 No newline at end of file