Make WordPress Core

Ticket #29256: miqro-29256.patch

File miqro-29256.patch, 13.2 KB (added by miqrogroove, 12 years ago)
  • src/wp-includes/formatting.php

     
    3030function wptexturize($text, $reset = false) {
    3131        global $wp_cockneyreplace;
    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, $closing_single_quote;
    3435
    3536        // If there's nothing to do, just stop.
    3637        if ( empty( $text ) || false === $run_texturize ) {
     
    105106                $dynamic_replacements = array( 'apos' => array(), 'quote' => array(), 'dash' => array() );
    106107                $dynamic = array();
    107108                $spaces = wp_spaces_regexp();
     109                $apos_flag = '<!--wp-apos-->';  // We need a semantic representation that is not identical to a quote.
    108110
    109111                // '99' and '99" are ambiguous among other patterns; assume it's an abbreviated year at the end of a quotation.
    110112                if ( "'" !== $apos || "'" !== $closing_single_quote ) {
    111                         $dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos . '$1' . $closing_single_quote;
     113                        $dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_single_quote;
    112114                }
    113115                if ( "'" !== $apos || '"' !== $closing_quote ) {
    114                         $dynamic[ '/\'(\d\d)"(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos . '$1' . $closing_quote;
     116                        $dynamic[ '/\'(\d\d)"(?=\Z|[.,)}\-\]]|&gt;|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_quote;
    115117                }
    116118
    117119                // '99 '99s '99's (apostrophe)  But never '9 or '99% or '999 or '99.0.
    118120                if ( "'" !== $apos ) {
    119                         $dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos;
     121                        $dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos_flag;
    120122                }
    121123
    122124                // Quoted Numbers like '0.42'
     
    131133
    132134                // Apostrophe in a word.  No spaces, double apostrophes, or other punctuation.
    133135                if ( "'" !== $apos ) {
    134                         $dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos;
     136                        $dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos_flag;
    135137                }
    136138
    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 
    147139                $dynamic_characters['apos'] = array_keys( $dynamic );
    148140                $dynamic_replacements['apos'] = array_values( $dynamic );
    149141                $dynamic = array();
     
    153145                        $dynamic[ '/(?<=\A|' . $spaces . ')"(\d[.,\d]*)"/' ] = $opening_quote . '$1' . $closing_quote;
    154146                }
    155147
    156                 // 9" (double prime)
    157                 if ( '"' !== $double_prime ) {
    158                         $dynamic[ '/(?<=\d)"/' ] = $double_prime;
    159                 }
    160 
    161148                // Double quote at start, or preceded by (, {, <, [, -, or spaces, and not followed by spaces.
    162149                if ( '"' !== $opening_quote ) {
    163150                        $dynamic[ '/(?<=\A|[([{\-]|&lt;|' . $spaces . ')"(?!' . $spaces . ')/' ] = $opening_quote;
    164151                }
    165152
    166                 // Any remaining double quotes.
    167                 if ( '"' !== $closing_quote ) {
    168                         $dynamic[ '/"/' ] = $closing_quote;
    169                 }
    170                
    171153                $dynamic_characters['quote'] = array_keys( $dynamic );
    172154                $dynamic_replacements['quote'] = array_values( $dynamic );
    173155                $dynamic = array();
     
    261243
    262244                        if ( false !== strpos( $curl, "'" ) ) {
    263245                                $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 );
    264248                        }
    265249                        if ( false !== strpos( $curl, '"' ) ) {
    266250                                $curl = preg_replace( $dynamic_characters['quote'], $dynamic_replacements['quote'], $curl );
     251                                $curl = wptexturize_primes( $curl, '"', $double_prime, $opening_quote, $closing_quote );
    267252                        }
    268253                        if ( false !== strpos( $curl, '-' ) ) {
    269254                                $curl = preg_replace( $dynamic_characters['dash'], $dynamic_replacements['dash'], $curl );
     
    285270}
    286271
    287272/**
     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 */
     285function 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|[.,)}\\-\\]]|&gt;|" . $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|[.,)}\\-\\]]|&gt;|" . $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/**
    288343 * Search for disabled element tags. Push element to stack on tag open and pop
    289344 * on tag close.
    290345 *
  • tests/phpunit/tests/formatting/WPTexturize.php

     
    9191                //$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.'));
    9292                //$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>".'));
    9393                //$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.'));
    94                 //$this->assertEquals('A test with a finishing number, &#8220;like 23&#8221;.', wptexturize('A test with a finishing number, "like 23".'));
    95                 //$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.'));
     94                $this->assertEquals('A test with a finishing number, &#8220;like 23&#8221;.', wptexturize('A test with a finishing number, "like 23".'));
     95                $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.'));
    9696        }
    9797
    9898        /**
     
    115115                $this->assertEquals('&#8216;Class of &#8217;99&#8217;', wptexturize("'Class of '99'"));
    116116                $this->assertEquals('&#8216;Class of &#8217;99&#8217;s&#8217;', wptexturize("'Class of '99's'"));
    117117                $this->assertEquals('&#8216;Class of &#8217;99&#8217;s&#8217;', wptexturize("'Class of '99&#8217;s'"));
    118                 //$this->assertEquals('&#8220;Class of 99&#8221;', wptexturize("\"Class of 99\""));
     118                $this->assertEquals('&#8220;Class of 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\"}"));
    121121                $this->assertEquals(' &#8220;Class of &#8217;99&#8221; ', wptexturize(" \"Class of '99\" "));
     
    17271727                        ),
    17281728                );
    17291729        }
     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&#8217;s porch is 99&#8242; long.",
     1746                        ),
     1747                        array(
     1748                                'The best year "was that time in 2012" when everyone partied, he said.',
     1749                                'The best year &#8220;was that time in 2012&#8221; 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&#8242; = 80&#8242; of trim.",
     1754                        ),
     1755                        array(
     1756                                '"Lorem ipsum dolor sit amet 1234"',
     1757                                '&#8220;Lorem ipsum dolor sit amet 1234&#8221;',
     1758                        ),
     1759                        array(
     1760                                "'Etiam eu egestas dui 1234'",
     1761                                "&#8216;Etiam eu egestas dui 1234&#8217;",
     1762                        ),
     1763                        array(
     1764                                'according to our source, "33% of all students scored less than 50" on the test.',
     1765                                'according to our source, &#8220;33% of all students scored less than 50&#8221; 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, &#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.",
     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
     1774As 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
     1776That 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
     1778String with a number followed by a single quote \'Expendables 3\' vestibulum in arcu mi.',
     1779
     1780                                '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.
     1781
     1782As 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.
     1783
     1784That 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.
     1785
     1786String with a number followed by a single quote &#8216;Expendables 3&#8217; vestibulum in arcu mi.',
     1787                        ),
     1788                );
     1789        }
    17301790}
     1791 No newline at end of file