Bug #77334 [Opn->Nab]: Issue with preg_replace shorthand character in character class
| From: | requinix@php.net | Date: | Fri, 21 Dec 2018 17:34:59 +0000 |
| Subject: | Bug #77334 [Opn->Nab]: Issue with preg_replace shorthand character in character class | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-218556@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=77334&edit=1
ID: 77334
Updated by: requinix@php.net
Reported by: webdev at westernseminary dot edu
Summary: Issue with preg_replace shorthand character in
character class
-Status: Open
+Status: Not a bug
Type: Bug
Package: *Regular Expressions
Operating System: Windows Server 2012
PHP Version: 7.3.0
Block user comment: N
Private report: N
New Comment:
It's not valid.
The reason for making it an error is because Perl would warn about the situation but PCRE2
isn't able to warn. If you don't like that then you need to file a bug report with them.
[0-9-.] works because the second hyphen is ignored because it works like a [-abc] or [abc-]
situation: the hyphen cannot possibly form a character range. In the case of [0-9-.] it's
because what came before is also a range and it cannot be "chained" into another range.
But \d does not mean [0-9]. It means [0123456789], plus some others when in Unicode mode. And
[0123456789-.] is not what you intended when you wrote [\d-.].
Previous Comments:
------------------------------------------------------------------------
[2018-12-21 17:30:57] webdev at westernseminary dot edu
Yes. However, should it throw an error? Isn't that a valid regular expression? Maybe there is a
bug in the new preg library?
If I swap the shorthand \d with 0-9, it works fine without throwing an error.
echo preg_replace('/[^0-9-\.]/', '', '123abc');
------------------------------------------------------------------------
[2018-12-21 17:28:27] requinix@php.net
PHP 7.3 upgraded to PCRE2 which does not allow metacharacters like \d to be used as endpoints of a
character range.
https://www.pcre.org/current/doc/html/pcre2pattern.html#SEC9
> Perl treats a hyphen as a literal if it appears before or after a POSIX class
> (see below) or before or after a character type escape such as as \d or \H.
> However, unless the hyphen is the last character in the class, Perl outputs a
> warning in its warning mode, as this is most likely a user error. As PCRE2 has
> no facility for warning, an error is given in these cases.
------------------------------------------------------------------------
[2018-12-21 17:17:57] danack@php.net
You might want to check the error message settings on your code. That code generates an error for me
on PHP 7.3.0: https://3v4l.org/NuLqI
Warning: preg_replace(): Compilation failed: invalid range in character class at offset 4 in
/in/NuLqI on line 3
Which explains why it's not working.
This is possibly related to the changed in the preg library used in PHP 7.3, but I'm on a
terrible network connection so hard to find the relevant link.
Escaping the hyphen makes it behave how you're expecting it to behave.
echo preg_replace('/[^\d\-\.]/', '', '123-abc');
------------------------------------------------------------------------
[2018-12-21 16:58:01] webdev at westernseminary dot edu
Description:
------------
When a shorthand character (\d) is used in a character class ([\d]) along wiht a dash and a dot, the
regular expression throws an error in PHP 7.3.0 even though the regular expression is valid. The
error does not occur in PHP 7.2.13.
Test script:
---------------
// SHORT EXAMPLE
echo preg_replace('/[^\d-\.]/', '', '123abc');
// LONG EXAMPLE
$value = '123abc';
$rgxs = array(
'/[\d]/',
'/[\d-]/',
'/[\d\.]/',
'/[\d-\.]/', //bug
'/[\d\.-]/',
'/[^\d]/',
'/[^\d-]/',
'/[^\d\.]/',
'/[^\d-\.]/', //bug
'/[^\w-\.]/', //bug
'/[^0-9-\.]/',
);
echo '<table border="1" cellpadding="10">';
echo '<tr>';
echo '<th>Index</th>';
echo '<th>Regular Expression</th>';
echo '<th>Result</th>';
echo '<th>Last Error</th>';
echo '</tr>';
foreach($rgxs as $i => $rgx) {
echo '<tr>';
echo '<td>'.$i.'</td>';
echo '<td>'.$rgx.'</td>';
echo '<td>'.preg_replace($rgx, '', $value).'</td>';
echo '<td>'.preg_last_error().'</td>';
echo '</tr>';
}
echo '</table>';
Expected result:
----------------
For the short example, the expected result would be "123".
Actual result:
--------------
For the short example, the actual result is NULL.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=77334&edit=1