正则表达式在所有后续匹配中使用捕获组

时间:2018-07-18 21:20:29

标签: regex

我不是很肯定这可以使用正则表达式语句来完成,但是我试图将第一个捕获的组放在每个后续数字之前,并使其他所有内容保持不变。 具体来说,我有一个用户输入的字符串:

-p

987ABC11-15; 77; 877; 66-68 之后的所有内容都可能发生变化-它可以为空白,也可以为数字,后跟数字,分号,空格和破折号的任意组合。

我想捕获该987ABC并将其放在其他数字的前面,以便它变为:

"ABC"

当前我正在尝试使用匹配字符串:

987ABC11-987ABC15; 987ABC77; 987ABC877; 987ABC66-987ABC68 

和替代:

/^([0-9]+[A-Za-z]+)([0-9]+)*([^0-9]+)*([0-9]+)*/g

但这只是将第一个捕获组放在最后一个捕获组的第一个实例之前,而不是所有实例之前。即变成:

$1$2$3$1$4

有什么想法吗?


更新: 我一直在尝试:

987ABC11-987ABC15; 77; 877; 66-68

并多次运行,我得到:

/([0-9]+[A-Za-z]+)(.*)([^0-9A-Za-z]+)([0-9]+)([^0-9A-Za-z])/$1$2$3$1$4$5/

涵盖了除68外的所有内容。 知道如何修改它以使其也达到68吗?

2 个答案:

答案 0 :(得分:2)

更新以提供仅模式化的解决方案,该解决方案需要循环触发,直到没有替换为止:

Pattern Demo

~(\d+[A-Z]+)(\d+[-; ]+)(\d+\b)~i/$1$2$1$3

Pattern Demo

~(\d+[A-Z]+)\d+[-; ]+\K(?=\d+\b)~i/$1

单词边界元字符\b阻止将前缀作为值进行匹配。


原始回复:

就像气泡一样,我将使用preg_replace_callback()调用并将捕获的前缀值作为可修改的全局变量进行携带,以便将其用于后续的子字符串替换。

代码:(Comparative PHP Demo)(Pattern Demo

$string = '987ABC11-15; 77; 877; 66-68';

$pattern = '~(^\d+[A-Z]+)?\d+\D+\K~';
echo preg_replace_callback($pattern, function($m)use(&$prefix) {
    if (isset($m[1])) $prefix = $m[1];
    return $prefix;
}, $string);
// output: 987ABC11-987ABC15; 987ABC77; 987ABC877; 987ABC66-987ABC68

我会否决bobble的答案,因为它很可靠,但我只想解释为什么我要发布这样的类似程序...

  • 通过使前导子字符串(前缀)捕获组为可选,并忽略已添加前缀的第一个“值”,我的解决方案仅执行了5次替换(逻辑上预期),而不是7次。

  • \K(全字符串匹配“ restarter”)可确保我从不“丢失”任何字符,因此不必在替换中重新插入任何字符。

  • 由于前缀捕获组是可选的,因此[1]中的$m键仅在第一次替换时出现。对于所有其他替换,不会生成[1]密钥。

  • 第一个替换调用在捕获组中传递前缀,并在15之前传递零宽度位置。我的解决方案不会单独传递前缀值,也不会覆盖11值之前的前缀。

p.s。我确实有一个在回调中使用空合并运算符的版本,但我并不觉得有任何好处(它每次都覆盖$prefix,而不是调用isset()),所以我报废了。我还拼命尝试使用static变量声明,但一直遇到警告,因此也被废弃了。

答案 1 :(得分:0)

腔室:必须多次运行:

/([0-9]+[A-Za-z]+)(.*)([^0-9A-Za-z]+)([0-9]+)([^0-9A-Za-z]|$)/$1$2$3$1$4$5

上运行
987ABC11-15; 77; 877; 66-68

成为

987ABC11-15; 77; 877; 66-987ABC68
987ABC11-15; 77; 877; 987ABC66-987ABC68
987ABC11-15; 77; 987ABC877; 987ABC66-987ABC68
987ABC11-15; 987ABC77; 987ABC877; 987ABC66-987ABC68
987ABC11-987ABC15; 987ABC77; 987ABC877; 987ABC66-987ABC68

这就是我想要的


更新: 我的一位同事指出了一些提高效率的方法:

/([0-9]+[A-Za-z])(.*[^0-9A-Za-z]+)([0-9]+)([^0-9A-Za-z]|$)/$1$2$1$3$4/
相关问题