替换两个字符之间的每个实例
Replace each instance between two characters
我在下面有以下数据,其中 {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);
问题在于它将两个 A 之间的所有实例替换为一个 C
。我如何修复我的正则表达式或 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
特征是一个anchor,可以在两个位置之一进行匹配;字符串位置的开始或最后一场比赛结束时的位置。 \K
转义序列重置报告匹配的起点,并且不再包含任何先前使用的字符。
要减少回溯量,您可以使用更复杂的表达式:
$str = preg_replace('~\G(?!\A)(?:{n}
|A(?:[^A]*A)+?((?=(?:{n})++A)\K{n}
|(*COMMIT)(*F)))
|[^A]*A(?:[^A]*A)*?(?1)~x', 'C', $str);
(?<=A){n}(?=(?:{n})*A)|\G(?!^){n}
你可以试试这个。替换为 C
。在这里你必须使用 \G
断言位置在前一个匹配的末尾或第一个匹配的字符串的开头。
这样您就可以在第一场比赛后进行比赛。请参阅演示。
https://regex101.com/r/wU4xK1/7
这里首先匹配 {n}
,它后面有 A
,后面有 A
,中间有 {n}
。捕获后,您使用 \G
重置为上一场比赛的结尾,随后继续替换 {n}
found.
$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);
稍微冗长但更容易遵循的解决方案是使用初始表达式将文本分成几组;然后在每个组内应用单独的转换:
$text = preg_replace_callback('~(?<=A)(?:\{n\})*(?=A)~', function($match) {
// simple replacement inside
return str_replace('{n}', 'C', $match[0]);
}, $text);
我通过使用 (?:...)
.
对表达式进行了一些小的调整,以消除不必要的内存捕获
我在下面有以下数据,其中 {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);
问题在于它将两个 A 之间的所有实例替换为一个 C
。我如何修复我的正则表达式或 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
特征是一个anchor,可以在两个位置之一进行匹配;字符串位置的开始或最后一场比赛结束时的位置。 \K
转义序列重置报告匹配的起点,并且不再包含任何先前使用的字符。
要减少回溯量,您可以使用更复杂的表达式:
$str = preg_replace('~\G(?!\A)(?:{n}
|A(?:[^A]*A)+?((?=(?:{n})++A)\K{n}
|(*COMMIT)(*F)))
|[^A]*A(?:[^A]*A)*?(?1)~x', 'C', $str);
(?<=A){n}(?=(?:{n})*A)|\G(?!^){n}
你可以试试这个。替换为 C
。在这里你必须使用 \G
断言位置在前一个匹配的末尾或第一个匹配的字符串的开头。
这样您就可以在第一场比赛后进行比赛。请参阅演示。
https://regex101.com/r/wU4xK1/7
这里首先匹配 {n}
,它后面有 A
,后面有 A
,中间有 {n}
。捕获后,您使用 \G
重置为上一场比赛的结尾,随后继续替换 {n}
found.
$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);
稍微冗长但更容易遵循的解决方案是使用初始表达式将文本分成几组;然后在每个组内应用单独的转换:
$text = preg_replace_callback('~(?<=A)(?:\{n\})*(?=A)~', function($match) {
// simple replacement inside
return str_replace('{n}', 'C', $match[0]);
}, $text);
我通过使用 (?:...)
.