我不是很肯定这可以使用正则表达式语句来完成,但是我试图将第一个捕获的组放在每个后续数字之前,并使其他所有内容保持不变。 具体来说,我有一个用户输入的字符串:
-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吗?
答案 0 :(得分:2)
更新以提供仅模式化的解决方案,该解决方案需要循环触发,直到没有替换为止:
~(\d+[A-Z]+)(\d+[-; ]+)(\d+\b)~i/$1$2$1$3
或
~(\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/