在文本开始之前匹配空白字符和多个可选模式的正则表达式

2024-05-19 19:28:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在解析包含如下代码的字符串。它可以从一个空行开始,后跟多个可选模式。这些模式可以是python风格的内联注释(使用散列字符),也可以是命令“!mycommand”,两者都必须从一行的开头开始。如何编写与代码开头匹配的正则表达式

mystring = """

# catch this comment
!mycommand
# catch this comment
#catch this comment too
!mycommand

# catch this comment
!mycommand
!mycommand

some code. match until the previous line
# do not catch this comment
!mycommand
# do not catch this comment
"""

import re
pattern = r'^\s*^#.*|!mycommand\s*'
m = re.search(pattern, mystring, re.MULTILINE)
mystring[m.start():m.end()]

mystring = 'code. do not match anything' + mystring
m = re.search(pattern, mystring, re.MULTILINE)

我希望正则表达式将字符串匹配到“some code.catch,直到前一行”。我尝试了不同的方法,但我可能被两种不同的模式困住了


Tags: 字符串代码rematch模式commentnotcode
3条回答

匹配并返回字符串开头的注释

不需要正则表达式,读取并将行追加到列表中,直到出现不以!#开头的行,并忽略所有空行:

mystring = "YOUR_STRING_HERE"

results = []
for line in mystring.splitlines():
  if not line.strip():                                      # Skip blank lines
    continue
  if not line.startswith('#') and not line.startswith('!'): # Reject if does not start with ! or #
    break
  else:
    results.append(line)                                    # Append comment

print(results)

Python demo。结果:

['# catch this comment', '!mycommand', '# catch this comment', '#catch this comment too', '!mycommand', '# catch this comment', '!mycommand', '!mycommand']

删除字符串开头的注释

results = []
flag = False
for line in mystring.splitlines():
  if not flag and not line.strip():
    continue
  if not flag and not line.startswith('#') and not line.startswith('!'):
    flag = True
  if flag:
    results.append(line)

print("\n".join(results))

输出:

some code. match until the previous line
# do not catch this comment
!mycommand
# do not catch this comment

this Python demo

正则表达式方法

import re
print(re.sub(r'^(?:(?:[!#].*)?\n)+', '', mystring))

如果行的开头有可选的缩进空格,请添加[^\S\n]*

print(re.sub(r'^(?:[^\S\n]*(?:[!#].*)?\n)+', '', mystring, count=1))

regex demoPython democount=1将确保我们只删除第一个匹配项(您不需要检查所有其他行)

正则表达式详细信息

  • ^-字符串的开头
  • (?:[^\S\n]*(?:[!#].*)?\n)+-1次或多次出现
    • [^\S\n]*-可选的水平空白
    • (?:[!#].*)?-一个可选的
      • [!#]-!#
      • .*-行的其余部分
    • \n-换行符

无需re.MULTILINE即可在匹配前后重复匹配0+个空格字符

^(?:\s*(?:#.*|!mycommand\s*))+\s*

Regex demoPython demo

比如说

import re
m = re.search(r'^(?:\s*(?:#.*|!mycommand\s*))+\s*', mystring)
print(m.group())

您的模式匹配# ...!mycommand的一个实例。解决此问题的一种方法是将所有的匹配项放在一个匹配项中,然后使用re.search查找第一个匹配项

为此,需要使用*重复匹配# ...!mycommand的部分:

^\s*^(?:#.*\s*|!mycommand\s*)*

我还将#.*更改为#.*\s*,这样它就一直转到下一行,在那里可以找到非空白

Demo

回应你的评论:

if the string begins with code, this regex should not match anything

您可以尝试:

\A\s*^(?:#.*\s*|!mycommand\s*)+

我改为\A,这样它只匹配字符串的绝对开头,而不是行的开头。我还将最后一个*更改为+,因此必须至少存在一个# ...!mycommand

相关问题 更多 >