下面有以下数据,其中{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}
我想用字母C
替换两个A字符之间占位符的每个实例。我为此编写了以下正则表达式,并且使用preg_replace
函数。
$str = preg_replace('~(?<=A)('{n'})*(?=A)~', 'C', $str);
问题是它用一个C
替换了两个A之间的所有实例。如何修复regex或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}
您可以通过锚定'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);
更详细但更易于遵循的解决方案是使用初始表达式将文本分组;然后在每组中应用单独的转换:
$text = preg_replace_callback('~(?<=A)(?:'{n'})*(?=A)~', function($match) {
// simple replacement inside
return str_replace('{n}', 'C', $match[0]);
}, $text);
我对表达式做了一个小的调整,通过使用(?:...)
来消除不必要的内存捕获。
(?<=A){n}(?=(?:{n})*A)|'G(?!^){n}
你可以试试这个。替换为C
。在这里,您必须使用'G
在上一个匹配的末尾或第一个匹配的字符串的开头断言位置。
这样你就可以在第一场比赛后进行比赛。请参阅演示。
https://regex101.com/r/wU4xK1/7
在这里,首先匹配后面有A
的{n}
和后面可以有{n}
的A
。捕获后,使用'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);