Ticket #18549: 18549_wptexturize.2.diff
File 18549_wptexturize.2.diff, 22.7 KB (added by , 9 years ago) |
---|
-
src/wp-includes/formatting.php
54 54 $closing_quote = null, 55 55 $opening_single_quote = null, 56 56 $closing_single_quote = null, 57 $open_q_flag = '<!--oq-->', 58 $open_sq_flag = '<!--osq-->', 59 $apos_flag = '<!--apos-->'; 57 $apos_flag, $open_sq_flag, $open_q_flag, $close_sq_flag, $close_q_flag, $prime_sq_flag, $prime_q_flag, $sq_flag, $q_flag, 58 $flags_sq, $flags_q, $reals_sq, $reals_q, 59 $nonsplit_regex, $comment_regex, 60 $static_no_texturize_shortcodes = null, $no_texturize_shortcode_regex, 61 $static_shortcode_tags = null, $shortcode_regex, 62 $spaces; 60 63 61 64 // If there's nothing to do, just stop. 62 65 if ( empty( $text ) || false === $run_texturize ) { … … 107 110 /* translators: em dash */ 108 111 $em_dash = _x( '—', 'em dash' ); 109 112 113 // Standardize size of flags to max of primes/quotes manipulated by wptexturize_primes(). 114 // This will allow wptexturize_primes() to do its replacements without worrying about offsets changing. 115 $dummy_len = max( 5, strlen( $closing_quote ), strlen( $prime ), strlen( $double_prime ), strlen( $closing_single_quote ) ); 116 117 $apos_flag = str_pad( '<i a>', $dummy_len, '>' ); 118 $open_sq_flag = str_pad( '<i o>', $dummy_len, '>' ); 119 $open_q_flag = str_pad( '<i O>', $dummy_len, '>' ); 120 $close_sq_flag = str_pad( '<i c>', $dummy_len, '>' ); 121 $close_q_flag = str_pad( '<i C>', $dummy_len, '>' ); 122 $prime_sq_flag = str_pad( '<i p>', $dummy_len, '>' ); 123 $prime_q_flag = str_pad( '<i P>', $dummy_len, '>' ); 124 $sq_flag = str_repeat( "'", $dummy_len ); 125 $q_flag = str_repeat( '"', $dummy_len ); 126 127 // Flags & reals arrays - used to reinstate the real values. 128 $flags_sq = array( $sq_flag, $prime_sq_flag, $open_sq_flag, $close_sq_flag, $apos_flag ); 129 $flags_q = array( $q_flag, $prime_q_flag, $open_q_flag, $close_q_flag ); 130 $reals_sq = array( "'", $prime, $opening_single_quote, $closing_single_quote, $apos ); 131 $reals_q = array( '"', $double_prime, $opening_quote, $closing_quote ); 132 110 133 $default_no_texturize_tags = array('pre', 'code', 'kbd', 'style', 'script', 'tt'); 111 134 $default_no_texturize_shortcodes = array('code'); 112 135 … … 139 162 140 163 // '99' and '99" are ambiguous among other patterns; assume it's an abbreviated year at the end of a quotation. 141 164 if ( "'" !== $apos || "'" !== $closing_single_quote ) { 142 $dynamic[ '/\'(\d\d)\'(?=\Z|[.,:;!?)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $clos ing_single_quote;165 $dynamic[ '/\'(\d\d)\'(?=\Z|[.,:;!?)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $close_sq_flag; 143 166 } 144 167 if ( "'" !== $apos || '"' !== $closing_quote ) { 145 $dynamic[ '/\'(\d\d)"(?=\Z|[.,:;!?)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $clos ing_quote;168 $dynamic[ '/\'(\d\d)"(?=\Z|[.,:;!?)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $close_q_flag; 146 169 } 147 170 148 171 // '99 '99s '99's (apostrophe) But never '9 or '99% or '999 or '99.0. … … 152 175 153 176 // Quoted Numbers like '0.42' 154 177 if ( "'" !== $opening_single_quote && "'" !== $closing_single_quote ) { 155 $dynamic[ '/(?<=\A|' . $spaces . ')\'(\d[.,\d]*)\'/' ] = $open_sq_flag . '$1' . $clos ing_single_quote;178 $dynamic[ '/(?<=\A|' . $spaces . ')\'(\d[.,\d]*)\'/' ] = $open_sq_flag . '$1' . $close_sq_flag; 156 179 } 157 180 158 181 // Single quote at start, or preceded by (, {, <, [, ", -, or spaces. … … 171 194 172 195 // Quoted Numbers like "42" 173 196 if ( '"' !== $opening_quote && '"' !== $closing_quote ) { 174 $dynamic[ '/(?<=\A|' . $spaces . ')"(\d[.,\d]*)"/' ] = $open_q_flag . '$1' . $clos ing_quote;197 $dynamic[ '/(?<=\A|' . $spaces . ')"(\d[.,\d]*)"/' ] = $open_q_flag . '$1' . $close_q_flag; 175 198 } 176 199 177 200 // Double quote at start, or preceded by (, {, <, [, -, or spaces, and not followed by spaces. … … 191 214 192 215 $dynamic_characters['dash'] = array_keys( $dynamic ); 193 216 $dynamic_replacements['dash'] = array_values( $dynamic ); 217 218 $nonsplit_regex = '\/?(?:a\b|abbr|b\b|big|br|dfn|em|i\b|samp|small|span|strong|sub|sup|var)[^>]*>'; 219 220 // Might as well initialize the comment regex once seeing as it's invariant. 221 $comment_regex = 222 '!' // Start of comment, after the <. 223 . '(?:' // Unroll the loop: Consume everything until --> is found. 224 . '-(?!->)' // Dash not followed by end of comment. 225 . '[^\-]*+' // Consume non-dashes. 226 . ')*+' // Loop possessively. 227 . '(?:-->)?'; // End of comment. If not found, match all input. 194 228 } 195 229 196 230 // Must do this every time in case plugins use these filters in a context sensitive manner … … 214 248 $no_texturize_tags_stack = array(); 215 249 $no_texturize_shortcodes_stack = array(); 216 250 217 // Look for shortcodes and HTML elements. 251 // Set up shortcodes regular expression (used to strip within each split text part), if haven't already or if things changed. 252 if ( $static_shortcode_tags === null || $shortcode_tags !== $static_shortcode_tags ) { 253 $static_shortcode_tags = $shortcode_tags; 254 $static_no_texturize_shortcodes = null; // Force reset of no texturize shortcodes as they need to be registered to be ignored. 255 $tagnames = array_keys( $shortcode_tags ); 256 if ( $tagnames ) { 257 $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) ); 258 $tagregexp = "(?:$tagregexp)(?![\\w-])"; // Excerpt of get_shortcode_regex(). 259 $shortcode_regex = 260 '|' 261 . '\[' // Find start of shortcode. 262 . '[\/\[]?' // Shortcodes may begin with [/ or [[ 263 . $tagregexp // Only match registered shortcodes, because performance. 264 . '(?:' 265 . '[^\[\]<>]+' // Shortcodes do not contain other shortcodes. Quantifier critical. 266 . '|' 267 . '<[^\[\]>]*>' // HTML elements permitted. Prevents matching ] before >. 268 . ')*+' // Possessive critical. 269 . '\]' // Find end of shortcode. 270 . '\]?'; // Shortcodes may end with ]] 271 } else { 272 $shortcode_regex = ''; 273 } 274 } 218 275 219 $tagnames = array_keys( $shortcode_tags ); 220 $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) ); 221 $tagregexp = "(?:$tagregexp)(?![\\w-])"; // Excerpt of get_shortcode_regex(). 276 // Set up no texturize shortcodes regular expression (used to split text input), if haven't already or if things changed. 277 if ( $static_no_texturize_shortcodes === null || $no_texturize_shortcodes !== $static_no_texturize_shortcodes ) { 278 $static_no_texturize_shortcodes = $no_texturize_shortcodes; 279 // No texturize shortcodes must also be registered to be ignored, so intersect with registered shortcodes array. 280 $tagnames = array_intersect( $no_texturize_shortcodes, array_keys( $static_shortcode_tags ) ); 281 if ( $tagnames ) { 282 $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) ); 283 $tagregexp = "(?:$tagregexp)(?![\\w-])"; // Excerpt of get_shortcode_regex(). 284 $no_texturize_shortcode_regex = 285 '|' 286 . '\[' // Find start of shortcode. 287 . '[\/\[]?' // Shortcodes may begin with [/ or [[ 288 . $tagregexp // Only match no texturize shortcodes. 289 . '(?:' 290 . '[^\[\]<>]+' // Shortcodes do not contain other shortcodes. Quantifier critical. 291 . '|' 292 . '<[^\[\]>]*>' // HTML elements permitted. Prevents matching ] before >. 293 . ')*+' // Possessive critical. 294 . '\]' // Find end of shortcode. 295 . '\]?'; // Shortcodes may end with ]] 296 } else { 297 $no_texturize_shortcode_regex = ''; 298 } 299 } 222 300 223 $comment_regex = 224 '!' // Start of comment, after the <. 225 . '(?:' // Unroll the loop: Consume everything until --> is found. 226 . '-(?!->)' // Dash not followed by end of comment. 227 . '[^\-]*+' // Consume non-dashes. 228 . ')*+' // Loop possessively. 229 . '(?:-->)?'; // End of comment. If not found, match all input. 301 // Look for comments, non-inline (non-split) HTML elements and no texturize shortcodes. 230 302 231 $shortcode_regex =232 '\[' // Find start of shortcode.233 . '[\/\[]?' // Shortcodes may begin with [/ or [[234 . $tagregexp // Only match registered shortcodes, because performance.235 . '(?:'236 . '[^\[\]<>]+' // Shortcodes do not contain other shortcodes. Quantifier critical.237 . '|'238 . '<[^\[\]>]*>' // HTML elements permitted. Prevents matching ] before >.239 . ')*+' // Possessive critical.240 . '\]' // Find end of shortcode.241 . '\]?'; // Shortcodes may end with ]]242 243 303 $regex = 244 304 '/(' // Capture the entire match. 245 305 . '<' // Find start of element. … … 246 306 . '(?(?=!--)' // Is this a comment? 247 307 . $comment_regex // Find end of comment. 248 308 . '|' 309 . '(?!' . $nonsplit_regex . ')' // Exclude inline html elements. 249 310 . '[^>]*>' // Find end of element. 250 311 . ')' 251 . '|' 252 . $shortcode_regex // Find shortcodes. 312 . $no_texturize_shortcode_regex // Find no texturize shortcodes. 253 313 . ')/s'; 254 314 255 $textarr = preg_split( $regex, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);315 $textarr = preg_split( $regex, $text, -1, PREG_SPLIT_DELIM_CAPTURE ); 256 316 257 foreach ( $textarr as &$curl ) { 258 // Only call _wptexturize_pushpop_element if $curl is a delimiter. 259 $first = $curl[0]; 260 if ( '<' === $first && '<!--' === substr( $curl, 0, 4 ) ) { 261 // This is an HTML comment delimeter. 317 foreach ( $textarr as $curl_idx => &$curl ) { 318 if ( 1 === $curl_idx % 2 ) { 319 // Delimiter. 320 $first = $curl[0]; 321 if ( '<' === $first ) { 322 // If not a comment. 323 if ( '<!--' !== substr( $curl, 0, 4 ) ) { 324 // This is an HTML element delimiter. 262 325 263 continue; 326 _wptexturize_pushpop_element( $curl, $no_texturize_tags_stack, $no_texturize_tags ); 327 } 328 } elseif ( '[' === $first ) { 329 // This is a shortcode delimiter. 264 330 265 } elseif ( '<' === $first && '>' === substr( $curl, -1 ) ) { 266 // This is an HTML element delimiter. 331 if ( '[[' !== substr( $curl, 0, 2 ) && ']]' !== substr( $curl, -2 ) ) { 332 // Looks like a normal shortcode. 333 _wptexturize_pushpop_element( $curl, $no_texturize_shortcodes_stack, $no_texturize_shortcodes ); 334 } else { 335 // Looks like an escaped shortcode. 336 } 337 } 338 } elseif ( empty( $no_texturize_shortcodes_stack ) && empty( $no_texturize_tags_stack ) && '' !== trim( $curl ) ) { 339 // This is neither a delimiter, nor is this content inside of no_texturize pairs. Do texturize. 267 340 268 _wptexturize_pushpop_element( $curl, $no_texturize_tags_stack, $no_texturize_tags ); 269 270 } elseif ( '' === trim( $curl ) ) { 271 // This is a newline between delimiters. Performance improves when we check this. 272 273 continue; 274 275 } elseif ( '[' === $first && 1 === preg_match( '/^' . $shortcode_regex . '$/', $curl ) ) { 276 // This is a shortcode delimiter. 277 278 if ( '[[' !== substr( $curl, 0, 2 ) && ']]' !== substr( $curl, -2 ) ) { 279 // Looks like a normal shortcode. 280 _wptexturize_pushpop_element( $curl, $no_texturize_shortcodes_stack, $no_texturize_shortcodes ); 281 } else { 282 // Looks like an escaped shortcode. 283 continue; 341 // Add a space to any <br>s so that when stripped will be recognized as whitespace. 342 if ( $have_br = ( false !== stripos( $curl, '<br' ) ) ) { 343 $curl = preg_replace( '/<br[^>]*>/i', '$0 ', $curl ); 284 344 } 285 345 286 } elseif ( empty( $no_texturize_shortcodes_stack ) && empty( $no_texturize_tags_stack ) ) { 287 // This is neither a delimiter, nor is this content inside of no_texturize pairs. Do texturize. 346 wptexturize_replace_init( $curl, '/<[^>]*>' . $shortcode_regex . '/' ); 288 347 289 $curl = str_replace( $static_characters, $static_replacements, $curl);348 wptexturize_replace_str( $curl, $static_characters, $static_replacements ); 290 349 291 350 if ( false !== strpos( $curl, "'" ) ) { 292 $curl = preg_replace( $dynamic_characters['apos'], $dynamic_replacements['apos'], $curl ); 293 $curl = wptexturize_primes( $curl, "'", $prime, $open_sq_flag, $closing_single_quote ); 294 $curl = str_replace( $apos_flag, $apos, $curl ); 295 $curl = str_replace( $open_sq_flag, $opening_single_quote, $curl ); 351 wptexturize_replace_regex( $curl, $dynamic_characters['apos'], $dynamic_replacements['apos'] ); 352 // Substitute single quotes with same-sized dummy so that wptexturize_primes() doesn't alter size of string. 353 wptexturize_replace_str( $curl, "'", $sq_flag ); 354 $curl = wptexturize_primes( $curl, $sq_flag, $prime_sq_flag, $open_sq_flag, $close_sq_flag, $spaces ); 355 // Reinstate real values. 356 wptexturize_replace_str( $curl, $flags_sq, $reals_sq ); 296 357 } 297 358 if ( false !== strpos( $curl, '"' ) ) { 298 $curl = preg_replace( $dynamic_characters['quote'], $dynamic_replacements['quote'], $curl ); 299 $curl = wptexturize_primes( $curl, '"', $double_prime, $open_q_flag, $closing_quote ); 300 $curl = str_replace( $open_q_flag, $opening_quote, $curl ); 359 wptexturize_replace_regex( $curl, $dynamic_characters['quote'], $dynamic_replacements['quote'] ); 360 // Substitute double quotes with same-sized dummy so that wptexturize_primes() doesn't alter size of string. 361 wptexturize_replace_str( $curl, '"', $q_flag ); 362 $curl = wptexturize_primes( $curl, $q_flag, $prime_q_flag, $open_q_flag, $close_q_flag, $spaces ); 363 // Reinstate real values. 364 wptexturize_replace_str( $curl, $flags_q, $reals_q ); 301 365 } 302 366 if ( false !== strpos( $curl, '-' ) ) { 303 $curl = preg_replace( $dynamic_characters['dash'], $dynamic_replacements['dash'], $curl);367 wptexturize_replace_regex( $curl, $dynamic_characters['dash'], $dynamic_replacements['dash'] ); 304 368 } 305 369 306 370 // 9x9 (times), but never 0x9999 307 371 if ( 1 === preg_match( '/(?<=\d)x\d/', $curl ) ) { 308 372 // Searching for a digit is 10 times more expensive than for the x, so we avoid doing this one! 309 $curl = preg_replace( '/\b(\d(?(?<=0)[\d\.,]+|[\d\.,]*))x(\d[\d\.,]*)\b/', '$1×$2', $curl );373 wptexturize_replace_regex( $curl, '/\b(\d(?(?<=0)[\d\.,]+|[\d\.,]*))x(?=\d[\d\.,]*\b)/', '$1×' ); // Changed to use look ahead as can only deal with a single sub-replacement. 310 374 } 375 376 wptexturize_replace_final( $curl ); 377 378 // Remove any spaces added to <br>s at the start. 379 if ( $have_br ) { 380 $curl = preg_replace( '/(<br[^>]*>) /i', '$1', $curl ); 381 } 311 382 } 312 383 } 313 384 $text = implode( '', $textarr ); … … 330 401 * @param string $close_quote The closing quote char to use for replacement. 331 402 * @return string The $haystack value after primes and quotes replacements. 332 403 */ 333 function wptexturize_primes( $haystack, $needle, $prime, $open_quote, $close_quote ) {334 $ spaces = wp_spaces_regexp();335 $flag = '<!--wp-prime-or-quote-->';404 function wptexturize_primes( $haystack, $needle, $prime, $open_quote, $close_quote, $spaces ) { 405 $flag = str_pad( '<i f>', strlen( $needle ), '>' ); // Making flag same size as the passed-in dummy. 406 $flag_len = strlen( $flag ); 336 407 $quote_pattern = "/$needle(?=\\Z|[.,:;!?)}\\-\\]]|>|" . $spaces . ")/"; 337 408 $prime_pattern = "/(?<=\\d)$needle/"; 338 409 $flag_after_digit = "/(?<=\\d)$flag/"; … … 359 430 // This is most likely to be problematic in the context of bug #18549. 360 431 $pos = strrpos( $sentence, $flag ); 361 432 } 362 $sentence = substr_replace( $sentence, $close_quote, $pos, strlen( $flag ));433 $sentence = substr_replace( $sentence, $close_quote, $pos, $flag_len ); 363 434 } 364 435 // Use conventional replacement on any remaining primes and quotes. 365 436 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 366 437 $sentence = preg_replace( $flag_after_digit, $prime, $sentence ); 367 438 $sentence = str_replace( $flag, $close_quote, $sentence ); 368 } elseif ( 1 == $count ) {439 } elseif ( 1 === $count ) { 369 440 // Found only one closing quote candidate, so give it priority over primes. 370 441 $sentence = str_replace( $flag, $close_quote, $sentence ); 371 442 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); … … 377 448 $sentence = preg_replace( $prime_pattern, $prime, $sentence ); 378 449 $sentence = preg_replace( $quote_pattern, $close_quote, $sentence ); 379 450 } 380 if ( '"' == $needle && false !== strpos( $sentence, '"') ) {381 $sentence = str_replace( '"', $close_quote, $sentence );451 if ( '"' === $needle[0] && false !== strpos( $sentence, $needle ) ) { 452 $sentence = str_replace( $needle, $close_quote, $sentence ); 382 453 } 383 454 } 384 455 … … 440 511 } 441 512 442 513 /** 514 * Initialize the stripped string routines wptexturize_replace_XXX, setting the globals used. 515 * $str will be stripped of any strings that match the regular expression $search. 516 */ 517 function wptexturize_replace_init( &$str, $search ) { 518 global $wptexturize_strip_cnt, $wptexturize_strips, $wptexturize_adjusts; 519 520 $wptexturize_strip_cnt = 0; 521 522 if ( preg_match_all( $search, $str, $matches, PREG_OFFSET_CAPTURE ) ) { 523 $wptexturize_strips = $wptexturize_adjusts = $strs = array(); 524 $diff = 0; 525 foreach ( $matches[0] as list( $match, $offset ) ) { 526 $len = strlen( $match ); 527 // Save details of stripped string. 528 $wptexturize_strips[] = array( $match, $offset - $diff /*, $len /* Store len if not using byte array in wptexturize_replace_final(). */ ); 529 $diff += $len; 530 $strs[] = $match; // If using str_replace rather than (safer) preg_replace. 531 } 532 $wptexturize_strip_cnt = count( $wptexturize_strips ); 533 $str = str_replace( $strs, '', $str ); // Assuming simple matches replaceable in whole string (otherwise need to do preg_replace( $search, '', $str )). 534 } 535 return $wptexturize_strip_cnt; 536 } 537 538 /** 539 * Do a straight (non-regexp) string substitution, keeping tabs on the offset adjustments if have a stripped string. 540 */ 541 function wptexturize_replace_str( &$str, $search, $repl ) { 542 global $wptexturize_strip_cnt, $wptexturize_adjusts; 543 544 if ( $wptexturize_strip_cnt ) { 545 // Process simple string search, given replacement string $repl. 546 $searches = is_array( $search ) ? $search : array( $search ); 547 $repls = is_array( $repl ) ? $repl : array( $repl ); 548 549 // As replacements could interfere with later ones, treat each separately. 550 foreach ( $searches as $idx => $search_str ) { 551 if ( false !== ( $offset = strpos( $str, $search_str ) ) ) { 552 $repl_str = $repls[$idx]; 553 $repl_len = strlen( $repl_str ); 554 $len = strlen( $search_str ); 555 $diff_len = $repl_len - $len; 556 if ( $diff_len ) { 557 $diff = 0; 558 do { 559 // Store adjustment details. 560 $wptexturize_adjusts[] = array( $offset + $diff, $repl_len - 1 ); 561 if ( $len > 1 ) { // Do it this way (rather than one adjust of $repl_len - $len) to keep adjustments "atomic", ie to keep stripped elements outside replacement. 562 $wptexturize_adjusts[] = array( $offset + $diff + $repl_len, 1 - $len ); 563 } 564 $diff += $diff_len; 565 } while ( false !== ( $offset = strpos( $str, $search_str, $offset + $len ) ) ); 566 } 567 $str = str_replace( $search_str, $repl_str, $str ); 568 } 569 } 570 } else { 571 $str = str_replace( $search, $repl, $str ); 572 } 573 } 574 575 /** 576 * Do a regexp string substitution, keeping tabs on the offset adjustments if have a stripped string. 577 */ 578 function wptexturize_replace_regex( &$str, $search, $repl ) { 579 global $wptexturize_strip_cnt, $wptexturize_adjusts; 580 581 if ( $wptexturize_strip_cnt ) { 582 // Process regex, given replacement string $repl. 583 $searches = is_array( $search ) ? $search : array( $search ); 584 $repls = is_array( $repl ) ? $repl : array( $repl ); 585 586 // As replacements could interfere with later ones, treat each separately. 587 foreach ( $searches as $idx => $re ) { 588 if ( preg_match_all( $re, $str, $matches, PREG_OFFSET_CAPTURE ) ) { 589 $repl_str = $repls[$idx]; 590 $repl_len = strlen( $repl_str ); 591 $diff = 0; 592 // Allow for a single captured replacement. 593 if ( false !== ( $pos1 = strpos( $repl_str, '$1' ) ) ) { 594 foreach ( $matches[0] as $i => list( $match, $offset ) ) { 595 // For a 'pre$1post' replacement, need to track pre-submatch replace and then post-submatch replace. 596 $pre_repl_len = $pos1; 597 $pre_len = $matches[1][$i][1] - $offset; // Submatch offset less full match offset. 598 if ( $pre_repl_len !== $pre_len ) { 599 // Store adjustment details. 600 $wptexturize_adjusts[] = array( $offset + $diff, $pre_repl_len - 1 ); 601 if ( $pre_len > 1 ) { // Keep adjustments atomic. 602 $wptexturize_adjusts[] = array( $offset + $diff + $pre_repl_len, 1 - $pre_len ); 603 } 604 $diff += $pre_repl_len - $pre_len; 605 } 606 $len1 = strlen( $matches[1][$i][0] ); // Length of submatch string. 607 $post_repl_len = $repl_len - ( $pre_repl_len + 2 ); 608 $post_len = strlen( $match ) - ( $pre_len + $len1 ); 609 if ( $post_repl_len !== $post_len ) { 610 // Store adjustment details. 611 $offset += $pre_len + $len1; // Jump over substituted pre-string & submatch. 612 $wptexturize_adjusts[] = array( $offset + $diff, $post_repl_len - 1 ); 613 if ( $post_len > 1 ) { // Keep adjustments atomic. 614 $wptexturize_adjusts[] = array( $offset + $diff + $post_repl_len, 1 - $post_len ); 615 } 616 $diff += $post_repl_len - $post_len; 617 } 618 } 619 } else { 620 foreach ( $matches[0] as list( $match, $offset ) ) { 621 $len = strlen( $match ); 622 if ( $repl_len !== $len ) { 623 // Store adjustment details. 624 $wptexturize_adjusts[] = array( $offset + $diff, $repl_len - 1 ); 625 if ( $len > 1 ) { // Keep adjustments atomic. 626 $wptexturize_adjusts[] = array( $offset + $diff + $repl_len, 1 - $len ); 627 } 628 $diff += $repl_len - $len; 629 } 630 } 631 } 632 $str = preg_replace( $re, $repl_str, $str ); 633 } 634 } 635 } else { 636 $str = preg_replace( $search, $repl, $str ); 637 } 638 } 639 640 /** 641 * Restore stripped strings to $str. 642 */ 643 function wptexturize_replace_final( &$str ) { 644 global $wptexturize_strip_cnt, $wptexturize_strips, $wptexturize_adjusts; 645 646 // Finalize - restore stripped strings. 647 if ( $wptexturize_strip_cnt ) { 648 // Calculate offset adjustments. 649 foreach ( $wptexturize_adjusts as list( $offset, $diff_len ) ) { 650 for ( $i = $wptexturize_strip_cnt - 1; $i >= 0 && $offset < $wptexturize_strips[$i][1]; $i-- ) { 651 $wptexturize_strips[$i][1] += $diff_len; 652 } 653 } 654 655 // Restore stripped strings. 656 $str_arr = str_split( $str ); // Using byte array (seems to be a bit quicker than substr_replace()). 657 array_unshift( $str_arr, '' ); 658 foreach ( $wptexturize_strips as list( $strip, $offset ) ) { 659 $str_arr[$offset] .= $strip; 660 } 661 $str = implode( '', $str_arr ); 662 unset( $str_arr ); 663 /* If not using byte array. (Note need to store $len in wptexturize_replace_init()). 664 $diff = 0; 665 foreach ( $wptexturize_strips as list( $strip, $offset, $len ) ) { 666 $str = substr_replace( $str, $strip, $offset + $diff, 0 ); 667 $diff += $len; 668 } 669 /**/ 670 $wptexturize_strip_cnt = 0; 671 } 672 } 673 674 /** 443 675 * Replaces double line-breaks with paragraph elements. 444 676 * 445 677 * A group of regex replaces used to identify text formatted with newlines and