如何在块内使用regexp进行搜索?

juzqafwq  于 2023-05-01  发布在  其他
关注(0)|答案(5)|浏览(89)

我有一个很长的文件,它由许多块组成,如下所示:

x=0
abc 20    
def 76   
ghi 11

x=1
def 45
ghi 32

x=2
jkl 56
mno 76
abc 134

.
.
.

x=393
xyz 21
abc 9

x=394
ghi 43
def 166
xyz 25

我需要正则表达式(对于Python)来获得以下输出:

return_list = [20,'x',134,...,9,'x']

(so abc和x的匹配应该被分配到同一组)
因此,我需要在每个块中查找abc是否可用,如果它在abc之后匹配整数,如果不匹配开头的'x'。每个块的块长度(行)都不同。
我试了一下regexp:(?ms)(?=x=\d).*?(?=\n\n)
它分别匹配所有块。我现在需要扩展在各个块中搜索abc,如果不存在则返回x。
我试过很多方法,但因为我是初学者,所以找不到解决办法。我希望有人能帮助我。

8yparm6h

8yparm6h1#

你可以用一个正则表达式来实现你想要的结果,通过改变你的正则表达式终止于abc = \d+\n\n\Z(以允许匹配字符串结尾的最后一组-这是你的示例数据所必需的,因为它没有以\n\n结束)。

(?ms)(?=x=\d).*?(?:abc (\d+)|\n\n|\Z)

如果块中存在abc = \d+,则将在组1中捕获数字,否则将为空。然后,您可以使用此事实将值替换为'x'

res = [m.group(1) or 'x' for m in re.finditer(r'(?ms)(?=x=\d).*?(?:abc (\d+)|\n\n|\Z)', data)]

输出:

['20', 'x', '134', '9', 'x']

注意,如果你想要整数而不是字符串,你可以稍微修改代码:

res = [int(m.group(1)) if m.group(1) else 'x' for m in re.finditer(r'(?ms)(?=x=\d).*?(?:abc (\d+)|\n\n|\Z)', data)]

输出:

[20, 'x', 134, 9, 'x']
cuxqih21

cuxqih212#

如果您可以使用PyPI regex,,这将是PCRE \K重置功能的一个很好的用途。

matches = regex.findall(r"(?m)^x(?:=(?>.+\n)*?abc \K\d+)?\b", s)

See this demo at regex101或www.example上的Python演示 www.example.com
x总是在^行开始处匹配,而它之后的整个组是 * 可选 *。如果可选部分匹配,则abc之后的新匹配将在\K\d+数字之前重置(并删除previous)。

svmlkihl

svmlkihl3#

这应该可以工作:

def processBlocks(inputString):
    # Break the string into blocks
    blocks = re.findall(r"(?s)(?:x=[0-9]+)(?:.(?!x=))*", inputString)
    result = []

    for block in blocks:
        # Check for "abc" followed by a number in this block
        number = re.search(r"abc ([0-9]+)", block)

        # If it's found, add it to the result. Otherwise, add "x".
        if number:
            result.append(int(number[1])) # Convert to actual int too.
        else:
            result.append("x")
    return result

与其尝试在一个正则表达式中完成所有事情(尽管这可能是可能的),将其分为两个步骤会更容易和更易读:首先,我们使用正则表达式将字符串分解为每个块,然后我们查看块中是否有“abc”后面跟着一个数字。如果我们找到一个数字,我们将它添加到结果列表中。否则,我们只需追加文字值“x”。

ocebsuys

ocebsuys4#

请您尝试以下方法:

#!/usr/bin/python

import re
with open('input_file') as f:
    s = f.read()

m = re.findall(r'(?ms)^x(?==\d+\n(?!(?:\w+ \d+\n)*^abc))|(?<=^abc )\d+', s)
print(m)

输出:

['20', 'x', '134', '9', 'x']
  • ^x(?==\d+\n(?!(?:\w+ \d+\n)*^abc))匹配x,如果它后面跟着一个=字符和一个数字,但在块中没有字符串abc
  • 如果上面的正则表达式不匹配,则使用(?<=^abc )\d+,前面有字符串abc的数字作为替代。
js81xvg6

js81xvg65#

您也可以交替使用单个捕获组,首先匹配以非空白字符开头的所有行,然后回溯到第一次出现的abc后跟一个数字,或x后跟一个数字

^(?:\S.*\n)*.*((?<=^abc )\d+|x(?==\d+$))

Regex demo|Python demo

相关问题