【问题标题】:preg_match behaviour unexpected on string \x00\x01字符串 \x00\x01 上的 preg_match 行为意外
【发布时间】:2018-08-16 09:47:19
【问题描述】:

我有一个循环,有时包含以下数据: b"\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00X\x1D›¿\x04\x04›?‹„\x12¿Ã’\x11?"

当我将它放入 regex101 时,我可以使用以下正则表达式匹配项目: /((\\x[\d]{2}){4,}.*)/gm

查看示例:https://regex101.com/r/cMyKVg/1/

当我把它放在我的 php 脚本中时,它是这样的:

preg_match( '/(x)/m', $value, $matches )

$value 具有上述字符串的值。

我没有使用此代码的匹配项。 我也尝试过逐字匹配:

preg_match( '/((\\x[\d]{2}){4,}.*)/m', 'b"\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00X\x1D›¿\x04\x04›?‹„\x12¿Ã’\x11?"', $matches ),

但它不匹配任何东西。

我不想在我的数据库中使用这个值,因此我想使用正则表达式来跳过这样的值。

有人可以向我解释这种行为并可能帮助解决它吗?

编辑: 我有一种感觉,我使用的字符串实际上并不是preg_match 中的内容,而是我使用var_dump 获得的值,但似乎preg_match 获得了不同的值。我不小心输入了一个错误,然后我收到了这条消息:

ErrorException  : preg_match(): Compilation failed: missing ) at offset 3

  at /Users/used/Sites/project/app/Console/Commands/ExtractLibraryFileMetaData.php:204
    200|            dd(
    201|                $value,
    202|                \gettype($value),
    203|                $regex = '/(\\)/',
  > 204|                preg_match( $regex, $value, $matches ),
    205|                $matches
    206|            );
    207|        }
    208|        if ( preg_match( '/((\\x[\d]{2}){4,}.*)/m', $value ) ) {

  Exception trace:

  1   preg_match("/(\)/", "\\\\\\\\\\X���?���Ò?")

我不知道是什么原因造成的。它仍然是相同的值,但显示方式不同...

【问题讨论】:

  • 我认为您的主要问题是输入是二进制字符串,而不是文本字符串。即\x00指的是NUL字节(U+0000)而不是文本"\x00"
  • 您确定您在问题中分享了确切的数据吗? '/(x)/m''b"\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00X\x1D›¿\x04\x04›?‹„\x12¿Ã’\x11?"' 没有意义
  • 你需要更多 \ -> 3v4l.org/US9Th
  • 这对我来说是 XY 问题的味道......

标签: php regex preg-match


【解决方案1】:

无论出于何种原因,PHP 中的 preg_match 似乎都需要三个反斜杠来正确转义 \x。我用这个正则表达式preg_match('/((?:\\\x[\d]{2}){4,}.*)/m', $str, $matches) 进行了测试,它成功了。

您可以在这里找到现场演示:http://sandbox.onlinephpfunctions.com/code/4aecc4bf25ec82a98c8fbaee32b34693f3316f64

【讨论】:

  • 不是“不管什么原因”——这是由于单引号字符串的语法造成的。
  • 由于某种原因,这对我不起作用。请看我的编辑。我认为这与此有关。
【解决方案2】:

查看左下角“工具”下的 regex101 code generator。您会看到正则表达式和与反斜杠相关的输入字符串都发生了一些更改。

您可以采用该方法或使用nowdoc,如下所示:

preg_match(<<< 'RE'
/(?:\\x\d{2}){4,}.*/
RE
,$str, $matches);

见 PHP live demo here

【讨论】:

  • 由于某种原因,这对我不起作用。请看我的编辑。我认为这与此有关。
【解决方案3】:

十六进制字符不作为字符串处理,字符串的实际输出大概是:

b"X›¿›?‹„¿Ã’?"

然后您可以使用十六进制范围进行匹配:

// I double-quoted the string
$str = "b\"\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00X\x1D›¿\x04\x04›?‹„\x12¿Ã’\x11?\"";

// Matches characters from char code 0 to 31
preg_match_all('/([\x00-\x1F])/', $str, $m);

输出:

echo '<pre>' . print_r($m[0], true) . '</pre>';

/*
Array
(
    [0] => 
    [1] => 
    [2] => 
    [3] => 
    [4] => 
    [5] => 
    [6] => 
    [7] => 
    [8] => 
    [9] => 
    [10] => 
    [11] => 
    [12] => 
    [13] => 
    [14] => 
    [15] => 
    [16] => 
)
*/

替换:

echo preg_replace('/([\x00-\x1F])/', '', $str);

// b"X›¿›?‹„¿Ã’?"

【讨论】:

  • 由于某种原因,这对我不起作用。请看我的编辑。我认为这与此有关。
  • @TheatreOfSouls 我更新了我的答案,告诉我它是否解决了你的问题
猜你喜欢
  • 1970-01-01
  • 2021-05-16
  • 1970-01-01
  • 1970-01-01
  • 2014-08-07
  • 2021-06-13
  • 2023-03-26
  • 1970-01-01
  • 2021-11-10
相关资源
最近更新 更多