Python re.sub 如何将字符串中的每个 0 替换为 2,当它旁边没有 1 时?

Python re.sub How to replace every 0 in a string with a 2 when there is no 1 directly next to it?

我对正则表达式完全陌生,现在我有以下任务:

我有一个看起来像这样的字符串:001000X00X001X00X

现在我想用 2 替换每个 0,当它旁边没有 1 且没有被 X 分隔时,因此示例字符串应更改为:001000X22X001X22X

我尝试使用类似这样的东西来做到这一点:

s = re.sub(r'X0+X', 'X2+X', s);

所以它搜索以 X 开头和结尾的子字符串,并且之间有一个随机数的“0”,但显然每个像这样的子字符串都被更改为 'X2+X'。 如何计算 0 的个数并将每个 0 替换为 2?

你可以使用

import re
s = '001000X00X001X00X'
print( re.sub(r'(?<=X)0+(?=X)', lambda x: '2' * len(x.group()), s) )
# => 001000X22X001X22X

## Or, if you also want to match start/end of string positions:
print( re.sub(r'(?<![^X])0+(?![^X])', lambda x: '2' * len(x.group()), s) )
# => 001000X22X001X22X

参见Python demo详情:

  • (?<=X)0+(?=X) 匹配一个或多个 0 字符,当此文本块紧跟在 X 字符
  • 之前和之后
  • (?<![^X])0+(?![^X]) - 匹配一个或多个 0 字符,这些字符以 X 或字符串开头并后跟 X 或字符串结尾
  • 一旦匹配,匹配的文本将替换为相同数量的 2 个字符。

使用 PyPi regex 模块(使用 pip install regex 安装在 terminal/console 中)您可以使用更简洁的

import regex
s = '00X00'
print( regex.sub(r'(?<=(?:^|X)0*)0(?=0*(?:X|$))', '2', s) )
# => 22X22

参见 this Python demo and this regex demo

(?<=(?:^|X)0*)0(?=0*(?:X|$)) 正则表达式匹配

  • (?<=(?:^|X)0*) - 紧接 X 或字符串开头的位置,然后是零个或多个 0 个字符
  • 0 - 零
  • (?=0*(?:X|$)) - 紧跟零个或多个 0 个字符的位置,然后是 X 或字符串结尾。

我提供正则表达式答案的速度太慢(@Wiktor Stribiżew,你太快了!),所以这里有一个使用拆分字符串作为中间值的替代方法:

'X'.join([re.sub('0', '2', i) if not '1' in i else i for i in s.split('X')])

如果字符串仅包含 0/1/X,这将是一个 simpler/faster 替代方案:

'X'.join(['2'*len(i) if not '1' in i else i for i in s.split('X')])

注意。在@JvdV 的评论之后,这是对@WiktorStribiżew 的回答的修正:

re.sub(r'(?<=X)0+(?=X)', lambda x: '2'*len(x.group()), 'X'+s+'X')[1:-1]

输出:'22X001000X22X001X22X'

您可以匹配 X 后跟 1 次或多次以查看右侧的 X 结尾的零,然后用 2

替换所有零

Regex demo | Python demo

import re

pattern = r"X0+(?=X)"
s = "001000X00X001X00X"

print(re.sub(pattern, lambda x: x.group().replace('0', '2'), s))

输出

001000X22X001X22X

如果您还想匹配 X 之前或之后的开头和结尾处的零,字符串的开头或结尾:

(?:X0+|^0+)(?=X|$)

Regex demo | Python demo

import re

strings = [
    "0X001000X00X001X00X0",
    "001000X00X001X00X",
    "000X000",
    "000"
]

pattern = r"(?:X0+|^0+)(?=X|$)"

for s in strings:
    print(re.sub(pattern, lambda x: x.group().replace('0', '2'), s))

输出

2X001000X22X001X22X2
001000X22X001X22X
222X222
222