【问题标题】:Parse string with regex and get desired output使用正则表达式解析字符串并获得所需的输出
【发布时间】:2019-07-26 11:54:42
【问题描述】:

我要解析这个字符串

[[delay-4]]Welcome! [[delay-2]]Do you have some questions for us?[[delay-1]] Please fill input field!

我需要这样的东西:

[
    [0] => '[[delay-4]]Welcome!',
    [1] => '[[delay-2]]Do you have some questions for us?',
    [2] => '[[delay-1]] Please fill input field!
];

字符串也可以是这样的(开头没有[[delay-4]]):

Welcome! [[delay-2]]Do you have some questions for us?[[delay-1]] Please fill input field!

预期的输出应该是这样的:

    [
        [0] => 'Welcome!',
        [1] => '[[delay-2]]Do you have some questions for us?',
        [2] => '[[delay-1]] Please fill input field!
    ];

我尝试了这个正则表达式 (https://regex101.com/r/Eqztl1/1/)

(?:\[\[delay-\d+]])?([\w \\,?!.@#$%^&*()|`\]~\-='\"{}]+)

但是,如果有人在文本中只写了一个 [,那么我的正则表达式就有问题,正则表达式会失败,如果我包含 [ 以匹配我得到错误的结果。

谁能帮我解决这个问题?

【问题讨论】:

标签: php regex pcre


【解决方案1】:

两个更简单的操作可能是获得结果的途径:

$result = preg_replace('/\s*(\[\[delay-\d+]])/i', "\n$1", $subject);
$result = preg_split('/\r?\n/i', $result, -1, PREG_SPLIT_NO_EMPTY);

可以看到这里运行: https://ideone.com/Z5tZI3 和这里: https://ideone.com/vnSNYI

这假定换行符没有特殊含义并且可以拆分。


更新:正如下面的 cmets 所述,可以进行一次拆分。

$result = preg_split('/(?=\[\[delay-\d+]])/i', $subject, -1, PREG_SPLIT_NO_EMPTY);

但是零长度匹配和正则表达式可能存在问题,您必须对此进行自己的研究。

【讨论】:

  • 如果字符串包含换行符怎么办?如果您通过前瞻更改捕获组,则只需使用第一个模式的 preg_split 即可完成此操作。 ] 不是特殊字符。
  • 当然可以 - 但是您必须注意零长度匹配的问题,这是一个需要解释的复杂问题。
  • 你在谈论什么样的问题?
  • 零长度匹配问题,其中一些在此处详细说明:regular-expressions.info/zerolength.html 请注意,尚不清楚这是如何影响preg_split
  • 3v4l.org/j3IeT :由于习惯,我从来没有把它视为一个问题!无论如何,既然你使用了PREG_SPLIT_NO_EMPTY 标志,这不是问题。
【解决方案2】:

在你的模式中

(?:[[delay-\d+]])?([\w \,?!.@#$%^&*()|`]~-='\"{}]+)上一页>

字符类中没有开口[。问题是如果你添加它,你会得到你所说的错误结果。

这是因为在匹配延迟后匹配后,现在包含[的下一部分中的字符类可以匹配包括延迟部分在内的其余字符。

您可以做的是添加 [ 并结合积极的前瞻来使匹配非贪婪,以断言延迟部分的下一个匹配或字符串的结尾也匹配最后一个实例。

如果你没有使用捕获组并且只想要结果,你可以省略它。

(?:\[\[delay-\d+]])?[\w \\,?!.@#$%^&*()|`[\]~\-='\"{}]+?(?=\[\[delay-\d+]]|$)

Regex demo | Php demo

【讨论】:

    【解决方案3】:

    您也可以在没有正则表达式的情况下做到这一点。

    [[ 上展开并循环数组。如果项目的开始是“延迟”则添加[[

    $str = '[[delay-4]]Welcome! [[delay-2]]Do you have some questions for us?[[delay-1]] Please fill input field!';
    
    $arr = array_filter(explode("[[", $str));
    
    foreach($arr as &$val){
        if(substr($val,0,5) == "delay") $val = "[[" . $val;
    }
    
    var_dump($arr);
    

    https://3v4l.org/sIui1

    【讨论】:

    • @AnantSingh---AlivetoDie 由于 OP 自己的正则表达式是硬编码的“延迟”,那么我认为我们可以假设这不是问题
    • 我同意,但除了当前答案之外,您仍然可以添加更通用的方式。我认为这没有什么害处:)。 3v4l.org/7H1AR3v4l.org/npM0p
    • 如果文本中出现带有模式“[[some text]]”的文本,这将失败。感谢你的回答! :)
    • @AleksaArsić 总是在您的问题中包含边缘案例。我们怎么知道它甚至可能有 [[some text]]?它很容易解决,但我认为这样做没有任何意义,因为我很确定很快就会有一个新案例出现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 2010-11-22
    相关资源
    最近更新 更多