Python 多行正则表达式分隔符
Python multiline regex delimiter
有这个多行变量:
raw = '''
CONTENT = ALL
TABLES = TEST.RAW_1
, TEST.RAW_2
, TEST.RAW_3
, TEST.RAW_4
PARALLEL = 4
'''
结构总是 TAG = CONTENT
,两个字符串都不是固定的,CONTENT
可以包含新行。
我需要一个regex
来获得:
[('CONTENT', 'ALL'), ('TABLES', 'TEST.RAW_1\n , TEST.RAW_2\n , TEST.RAW_3\n , TEST.RAW_4\n'), ('PARALLEL', '4')]
尝试了多种组合,但我无法 停止 regex
引擎 TABLES
标签,因为它的内容是由下一个标签分隔的 多行字符串 。
一些尝试来自口译员:
>>> re.findall(r'(\w+?)\s=\s(.+?)', raw, re.DOTALL)
[('CONTENT', 'A'), ('TABLES', 'T'), ('PARALLEL', '4')]
>>> re.findall(r'^(\w+)\s=\s(.+)?', raw, re.M)
[('CONTENT', 'ALL'), ('TABLES', 'TEST.RAW_1'), ('PARALLEL', '4')]
>>> re.findall(r'(\w+)\s=\s(.+)?', raw, re.DOTALL)
[('CONTENT', 'ALL\nTABLES = TEST.RAW_1\n , TEST.RAW_2\n , TEST.RAW_3\n , TEST.RAW_4\nPARALLEL = 4\n')]
谢谢!
您可以使用积极的前瞻来确保您懒惰地正确匹配值:
(\w+)\s=\s(.+?)(?=$|\n[A-Z])
^^^^^^^^^^^^
与 DOTALL 修饰符一起使用,以便 .
可以匹配换行符。 (?=$|\n[A-Z])
前瞻将要求 .+?
匹配到字符串的末尾,或者匹配到后跟大写字母的换行符。
参见regex demo。
还有替代方案,更快的正则表达式(因为它是上述表达式的展开版本)- 但 DOTALL 修饰符不应与它一起使用:
(\w+)\s*=\s*(.*(?:\n(?![A-Z]).*)*)
解释:
(\w+)
- 第 1 组捕获 1+ 个单词字符
\s*=\s*
- =
符号用可选的 (0+) 空格包裹
(.*(?:\n(?![A-Z]).*)*)
- 第 2 组捕获 0+ 个序列:
.*
- 除换行符外的任何 0+ 个字符
(?:\n(?![A-Z]).*)*
- 0+ 个序列:
\n(?![A-Z])
- 换行符后面没有大写 ASCII 字母
.*
- 除换行符外的任何 0+ 个字符
import re
p = re.compile(r'(\w+)\s=\s(.+?)(?=$|\n[A-Z])', re.DOTALL)
raw = '''
CONTENT = ALL
TABLES = TEST.RAW_1
, TEST.RAW_2
, TEST.RAW_3
, TEST.RAW_4
PARALLEL = 4
'''
print(p.findall(raw))
有这个多行变量:
raw = '''
CONTENT = ALL
TABLES = TEST.RAW_1
, TEST.RAW_2
, TEST.RAW_3
, TEST.RAW_4
PARALLEL = 4
'''
结构总是 TAG = CONTENT
,两个字符串都不是固定的,CONTENT
可以包含新行。
我需要一个regex
来获得:
[('CONTENT', 'ALL'), ('TABLES', 'TEST.RAW_1\n , TEST.RAW_2\n , TEST.RAW_3\n , TEST.RAW_4\n'), ('PARALLEL', '4')]
尝试了多种组合,但我无法 停止 regex
引擎 TABLES
标签,因为它的内容是由下一个标签分隔的 多行字符串 。
一些尝试来自口译员:
>>> re.findall(r'(\w+?)\s=\s(.+?)', raw, re.DOTALL)
[('CONTENT', 'A'), ('TABLES', 'T'), ('PARALLEL', '4')]
>>> re.findall(r'^(\w+)\s=\s(.+)?', raw, re.M)
[('CONTENT', 'ALL'), ('TABLES', 'TEST.RAW_1'), ('PARALLEL', '4')]
>>> re.findall(r'(\w+)\s=\s(.+)?', raw, re.DOTALL)
[('CONTENT', 'ALL\nTABLES = TEST.RAW_1\n , TEST.RAW_2\n , TEST.RAW_3\n , TEST.RAW_4\nPARALLEL = 4\n')]
谢谢!
您可以使用积极的前瞻来确保您懒惰地正确匹配值:
(\w+)\s=\s(.+?)(?=$|\n[A-Z])
^^^^^^^^^^^^
与 DOTALL 修饰符一起使用,以便 .
可以匹配换行符。 (?=$|\n[A-Z])
前瞻将要求 .+?
匹配到字符串的末尾,或者匹配到后跟大写字母的换行符。
参见regex demo。
还有替代方案,更快的正则表达式(因为它是上述表达式的展开版本)- 但 DOTALL 修饰符不应与它一起使用:
(\w+)\s*=\s*(.*(?:\n(?![A-Z]).*)*)
解释:
(\w+)
- 第 1 组捕获 1+ 个单词字符\s*=\s*
-=
符号用可选的 (0+) 空格包裹(.*(?:\n(?![A-Z]).*)*)
- 第 2 组捕获 0+ 个序列:.*
- 除换行符外的任何 0+ 个字符(?:\n(?![A-Z]).*)*
- 0+ 个序列:\n(?![A-Z])
- 换行符后面没有大写 ASCII 字母.*
- 除换行符外的任何 0+ 个字符
import re
p = re.compile(r'(\w+)\s=\s(.+?)(?=$|\n[A-Z])', re.DOTALL)
raw = '''
CONTENT = ALL
TABLES = TEST.RAW_1
, TEST.RAW_2
, TEST.RAW_3
, TEST.RAW_4
PARALLEL = 4
'''
print(p.findall(raw))