使用 preg_replace_callback 返工 preg_replace
rework preg_replace with preg_replace_callback
我已经看到很多关于这个的答案,但由于这个有点具体,我仍然需要一些帮助。我正在尝试更新 Blogstudio 的 Fix Serialization 脚本,其中包含 preg_replace()
和 \e
修饰符。
有问题的代码是这样的:
$data = preg_replace('!s:(\d+):([\\]?"[\\]?"|[\\]?"((.*?)[^\\])[\\]?");!e', "'s:'.strlen(unescape_mysql('')).':\"'.unescape_quotes('').'\";'", $data);
我的困惑在于:
- 这些函数是否打算解决由于
/e
修饰符引起的转义引号?
- 没有
</code> 时结果应该是什么?</li>
</ol>
<p>我已将其重写为这样,但仍然 运行 出现警告和其他问题,因此结果与预期的不一样:</p>
<pre><code>$data = preg_replace_callback(
'!s:(\d+):([\\]?"[\\]?"|[\\]?"((.*?)[^\\])[\\]?");!',
function($d) {
$length = strlen(unescape_mysql($d[3]));
$value = unescape_quotes($d[3]);
$result = 's:' . $length . ':\"' . $value . '\";';
return 's:' . $length . ':\"' . $value . '\";'
},
$data
);
问题:
s:(\d+): # group 1
( # group 2
[\\]?"[\\]?"
|
[\\]?"
((.*?)[^\\]) # group 3 (and 4)
[\\]?"
)
;
如您所见,组 2 中有 2 个分支的交替。组 3(和 4)在第二个分支中,当第一个分支成功时,这些组未定义。
让我们清理模式,删除无用的捕获组:
s:\d+:
(?:
[\\]? " [\\]? "
|
[\\]? "
(.*? [^\\]) # group 1
[\\]? "
)
;
现在目标组是组1,但是分支问题依旧。有两种可能的解决方法:
- 可以在回调函数中
isset
测试索引是否存在
- 您可以使用分支重置功能以在两个分支中定义组 1 的方式更改模式。
第一种方式:
$data = preg_replace_callback(
'~s:\K\d+:(?:[\\]?"[\\]?"|[\\]?"(.*?[^\\])[\\]?");~',
function ($m) {
return (isset($m[1]))
? strlen(unescape_mysql($m[1])) . ':\"' . $m[1] . '\";'
: '0:\"\";';
},
$data
);
第二种方式(具有分支重置功能):
$data = preg_replace_callback(
'~s:\K\d+:(?|[\\]?"[\\]?"()|[\\]?"(.*?[^\\])[\\]?");~',
function ($m) {
return strlen(unescape_mysql($m[1])) . ':\"' . $m[1] . '\";';
},
$data
);
在分支重置组捕获组在每个分支中具有相同的编号,要解决您的问题,您只需在第一个分支中创建一个空捕获组:
(?| # open a branch reset group
foo
() # capture group 1
|
bar
(baz) # capture group 1 (too)
)
我已经看到很多关于这个的答案,但由于这个有点具体,我仍然需要一些帮助。我正在尝试更新 Blogstudio 的 Fix Serialization 脚本,其中包含 preg_replace()
和 \e
修饰符。
有问题的代码是这样的:
$data = preg_replace('!s:(\d+):([\\]?"[\\]?"|[\\]?"((.*?)[^\\])[\\]?");!e', "'s:'.strlen(unescape_mysql('')).':\"'.unescape_quotes('').'\";'", $data);
我的困惑在于:
- 这些函数是否打算解决由于
/e
修饰符引起的转义引号? - 没有
</code> 时结果应该是什么?</li> </ol> <p>我已将其重写为这样,但仍然 运行 出现警告和其他问题,因此结果与预期的不一样:</p> <pre><code>$data = preg_replace_callback( '!s:(\d+):([\\]?"[\\]?"|[\\]?"((.*?)[^\\])[\\]?");!', function($d) { $length = strlen(unescape_mysql($d[3])); $value = unescape_quotes($d[3]); $result = 's:' . $length . ':\"' . $value . '\";'; return 's:' . $length . ':\"' . $value . '\";' }, $data );
问题:
s:(\d+): # group 1
( # group 2
[\\]?"[\\]?"
|
[\\]?"
((.*?)[^\\]) # group 3 (and 4)
[\\]?"
)
;
如您所见,组 2 中有 2 个分支的交替。组 3(和 4)在第二个分支中,当第一个分支成功时,这些组未定义。
让我们清理模式,删除无用的捕获组:
s:\d+:
(?:
[\\]? " [\\]? "
|
[\\]? "
(.*? [^\\]) # group 1
[\\]? "
)
;
现在目标组是组1,但是分支问题依旧。有两种可能的解决方法:
- 可以在回调函数中
isset
测试索引是否存在 - 您可以使用分支重置功能以在两个分支中定义组 1 的方式更改模式。
第一种方式:
$data = preg_replace_callback(
'~s:\K\d+:(?:[\\]?"[\\]?"|[\\]?"(.*?[^\\])[\\]?");~',
function ($m) {
return (isset($m[1]))
? strlen(unescape_mysql($m[1])) . ':\"' . $m[1] . '\";'
: '0:\"\";';
},
$data
);
第二种方式(具有分支重置功能):
$data = preg_replace_callback(
'~s:\K\d+:(?|[\\]?"[\\]?"()|[\\]?"(.*?[^\\])[\\]?");~',
function ($m) {
return strlen(unescape_mysql($m[1])) . ':\"' . $m[1] . '\";';
},
$data
);
在分支重置组捕获组在每个分支中具有相同的编号,要解决您的问题,您只需在第一个分支中创建一个空捕获组:
(?| # open a branch reset group
foo
() # capture group 1
|
bar
(baz) # capture group 1 (too)
)