【问题标题】:preg_replace_callback: including curly braces in a pattern: { is captured, } isn'tpreg_replace_callback:在模式中包含花括号:{ 被捕获,} 不是
【发布时间】:2018-02-12 01:54:01
【问题描述】:

我有这个函数,它利用 preg_replace_callback 将一个句子分成属于不同类别(字母、汉字、其他所有字符)的块的“链”。

该函数正在尝试将字符 '{} 包含为“字母”

function String_SplitSentence($string)
{
 $res = array();

 preg_replace_callback("~\b(?<han>\p{Han}+)\b|\b(?<alpha>[a-zA-Z0-9{}']+)\b|(?<other>[^\p{Han}A-Za-z0-9\s]+)~su",
 function($m) use (&$res) 
 {
 if (!empty($m["han"])) 
 {
  $t = array("type" => "han", "text" => $m["han"]);
  array_push($res,$t);
 }
 else if (!empty($m["alpha"])) 
 {
  $t = array("type" => "alpha", "text" => $m["alpha"]);
  array_push($res, $t);
 }
 else  if (!empty($m["other"])) 
 {
  $t = array("type" => "other", "text" => $m["other"]);
  array_push($res, $t);
 }
 },
 $string);

 return $res;
}

但是,花括号似乎有问题。

print_r(String_SplitSentence("Many cats{1}, several rats{2}"));

从输出中可以看出,该函数将 { 视为字母字符,如所示,但在 } 处停止并将其视为“其他”。

Array
(
    [0] => Array
        (
            [type] => alpha
            [text] => Many
        )

    [1] => Array
        (
            [type] => alpha
            [text] => cats{1
        )

    [2] => Array
        (
            [type] => other
            [text] => },
        )

    [3] => Array
        (
            [type] => alpha
            [text] => several
        )

    [4] => Array
        (
            [type] => alpha
            [text] => rats{2
        )

    [5] => Array
        (
            [type] => other
            [text] => }
        )

我做错了什么?

【问题讨论】:

  • 我无法复制您的问题。在 3v4l 中运行您的代码会发现您的正则表达式 works as expected
  • 字符类拼写错误? a-zA-Z0-9}'?您的字母字符类中有},但没有{。那是猴子扳手吗?你的模式中没有.,所以s 标志是不必要的。你运行的是什么 php 版本?您的预期结果是什么。
  • 对不起大家,我在测试时粘贴了代码 includig only }。现在我在正则表达式中添加了 { 和 } 。也许我还应该指定:php 7.0
  • 我的预期结果是 [1] => Array([type] => alpha[text] => cats{1})

标签: php regex unicode word-boundary named-captures


【解决方案1】:

我不能完全确定,因为您的示例输入不代表任何中文字符,而且我不知道您可能会尝试处理什么样的边缘案例,但这是我编写模式的方式:

~(?<han>\p{Han}+)|(?<alpha>[a-z\d{}']+)|(?<other>\S+)~ui

\b 的问题在于它正在寻找\w 字符。 \w 代表大写字母、小写字母、数字和下划线。参考:https://stackoverflow.com/a/11874899/2943403

此外,您的模式不包含任何 .s,因此您可以删除 s 模式修饰符。


您的函数调用似乎也在滥用preg_replace_callback()。我的意思是,你实际上并没有替换任何东西,所以这是一个不恰当的调用。也许你可以考虑这样重写:

function String_SplitSentence($string){
    if(!preg_match_all("~(?<han>\p{Han}+)|(?<alpha>[a-z\d{}']+)|(?<other>\S+)~ui",$string,$out)){
        return [];  // or $string or false
    }else{
        foreach($out as $group_key=>$group){
            if(!is_numeric($group_key)){  // disregard the indexed groups (which are unavoidably generated)
                foreach($group as $i=>$v){
                    if(strlen($v)){  // only store the value in the subarray that has a string length
                        $res[$i]=['type'=>$group_key,'text'=>$v];
                    }
                }
            }
        }
        ksort($res);
        return $res;
    }
}

关于你的模式的演示:https://regex101.com/r/6EUaSM/1

\b 在你的角色类把它搞砸之后。 } 不包含在 \w 类中。正则表达式希望为您做好工作——它“贪婪地”捕获,直到它不再能捕获。 } 由于单词边界而被排除在外。

【讨论】:

  • @resle 如果您有任何我的模式失败的边缘情况,请提供输入字符串和预期输出。
  • 谢谢,到目前为止这似乎有效。您能否具体解释一下为什么“{”被捕获但 } 没有被捕获?
  • 为您添加了更多内容
  • 谢谢,明白了。也可以完美地与中文字符一起使用。您可能需要添加 ksort($res) 否则返回的“块”的顺序不符合原始句子的顺序。
  • 修复了按键。好建议。
猜你喜欢
  • 2013-06-17
  • 2016-11-30
  • 1970-01-01
  • 2020-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-05
  • 1970-01-01
相关资源
最近更新 更多