我在下面的数据中{n}
表示占位符。
{n}{n}A{n}{n}A{n}
{n}A{n}{n}{n}{n}A
{n}{n}A{n}A{n}{n}
{n}{n}{n}A{n}A{n}B
{n}A{n}{n}B{n}{n}
A{n}B{n}{n}{n}{n}
我想用两个A字符替换占位符的每个实例,例如字母C
。我为此编写了以下正则表达式,并且我使用了preg_replace
函数。
$str = preg_replace('~(?<=A)(\{n\})*(?=A)~', 'C', $str);
问题在于它用两个C
替换了两个A之间的所有实例。如何修复我的正则表达式或preg_replace
调用以用C
替换占位符的每个单独实例?
这应该是我的输出。
{n}{n}ACCA{n}
{n}ACCCCA
{n}{n}ACA{n}{n}
{n}{n}{n}ACA{n}B
{n}A{n}{n}B{n}{n}
A{n}B{n}{n}{n}{n}
但目前它输出了这个。
{n}{n}ACA{n}
{n}ACA
{n}{n}ACA{n}{n}
{n}{n}{n}ACA{n}B
{n}A{n}{n}B{n}{n}
A{n}B{n}{n}{n}{n}
答案 0 :(得分:8)
您可以使用\G
进行锚定来解决问题。
$str = preg_replace('~(?:\G(?!\A)|({n})*A(?=(?1)++A))\K{n}~', 'C', $str);
\G
功能是一个可以在两个位置之一匹配的锚点;字符串位置的开头或最后一个匹配结束时的位置。 \K
转义序列重置报告的匹配的起始点,并且不再包括任何以前消耗的字符。
为了减少回溯量,您可以使用更复杂的表达式:
$str = preg_replace('~\G(?!\A)(?:{n}
|A(?:[^A]*A)+?((?=(?:{n})++A)\K{n}
|(*COMMIT)(*F)))
|[^A]*A(?:[^A]*A)*?(?1)~x', 'C', $str);
答案 1 :(得分:7)
更详细但更容易理解的解决方案是使用初始表达式将文本分成组;然后在每个组中应用单个转换:
$text = preg_replace_callback('~(?<=A)(?:\{n\})*(?=A)~', function($match) {
// simple replacement inside
return str_replace('{n}', 'C', $match[0]);
}, $text);
我使用(?:...)
对表达式进行了一些小调整以消除内存捕获,这是不必要的。
答案 2 :(得分:4)
(?<=A){n}(?=(?:{n})*A)|\G(?!^){n}
你可以试试这个。替换为C
。在这里,您必须使用\G
来确定上一场比赛结束时的位置或第一场比赛的字符串开头。
这样你就可以在第一场比赛后进行比赛。见演示。
https://regex101.com/r/wU4xK1/7
首先,您匹配{n}
后面有A
的{{1}}和A
后面的{n}
。捕获后,您使用\G
重置为上一个匹配结束,然后继续替换找到的{n}
。
$re = "/(?<=A){n}(?=(?:{n})*A)|\\G(?!^){n}/";
$str = "{n}{n}A{n}{n}A{n}\n{n}A{n}{n}{n}{n}A\n{n}{n}A{n}A{n}{n}\n{n}{n}{n}A{n}A{n}B\n{n}A{n}{n}B{n}{n}\nA{n}B{n}{n}{n}{n}";
$subst = "C";
$result = preg_replace($re, $subst, $str);