【问题标题】:Python regular expression not extracting value - Python 3.xPython 正则表达式不提取值 - Python 3.x
【发布时间】:2020-01-28 13:56:09
【问题描述】:

我正在循环浏览一个非常大 (~5GB) 的文本文档,如下所示:

<P ID=912>
bird
dog
dog
dog
</P>

<P ID=5>
aardvark
bird
bird
cat
egret
</P>

<P ID=291>
aardvark
aardvark
aardvark
aardvark
aardvark
bird
dog
fish
fish
fish
</P>

<P ID=621>
aardvark
aardvark
bird
dog
fish
fish
fish
</P>

<P ID=5>
bird
egret
egret
</P>

<P ID=1>
bird
</P>

从 ID 没有组织的意义上说,文档非常“无序”。我需要创建一个循环遍历每个段落的解决方案(由 &lt;P ID = x&gt;&lt;/P&gt; 标记表示,它将始终存在),并提取 ID 号。

我正在使用NLTK 标记段落,效果很好,我的问题是我无法从标签中提取ID

import nltk
from nltk.tokenize import word_tokenize, RegexpTokenizer
import re

def get_input(filepath):
    f = open(filepath, 'r')
    content = f.read()
    return content

def main():
    myfile = get_input("filepath")
    p = r'<P ID=\d+>(.*?)</P>'    
    paras = RegexpTokenizer(p)
    para_id = 0

    for para in paras.tokenize(myfile):
        para_id = re.match("<P ID=\d+>", para)        
        print("Current paragraph Number: {}".format(para_id))

main()

导致:

Current paragraph Number: None
Current paragraph Number: None
Current paragraph Number: None
Current paragraph Number: None
Current paragraph Number: None
Current paragraph Number: None

但我希望它看起来像:

Current paragraph Number: 912
Current paragraph Number: 5
Current paragraph Number: 291
Current paragraph Number: 621
Current paragraph Number: 5
Current paragraph Number: 1

需要怎么改:para_id = re.match("&lt;P ID=\d+&gt;", para)

编辑: 我也试过: para_id = [i['id'] for i in soup(para, 'html.parser').find_all('p')] 但这会产生一个空白 [] 我不知道为什么我不能创建一个只有单数段落的汤

注意- 我应该提到这是代码的最小示例。真正的程序要大得多,并且需要 NLTK 来解析,因为我在停用词和文本标记化方面做了很多工作。

【问题讨论】:

  • 您可能只需要re.search 而不是re.match
  • 不幸的是,将 re.match 更改为 re.search 会产生相同的结果。

标签: python regex python-3.x beautifulsoup nltk


【解决方案1】:

您在捕获段落文本但 您应该捕获包括 P 标签在内的完整段落, 之后你捕获了段落的ID,我在data.txt中使用了你的简单:

from nltk.tokenize import word_tokenize, RegexpTokenizer
import re

def get_input(filepath):
    f = open(filepath, 'r')
    content = f.read()
    f.close()  # don't forget to close file
    return content

def main():
    myfile = get_input("data.txt")
    # here capture the full paragraph
    p = r'<P ID=\d+>.*?</P>'
    paras = RegexpTokenizer(p)
    para_id = 0
    for para in paras.tokenize(myfile):
        # and here just catch the ID
        para_id = re.match("<P ID=(\d+)>", para)
        print("Current paragraph Number: {}".format(para_id.group(1)))

main()

输出:

Current paragraph Number: 912
Current paragraph Number: 5
Current paragraph Number: 291
Current paragraph Number: 621
Current paragraph Number: 5
Current paragraph Number: 1

您正在阅读整个 5 GB 文件,我认为您应该为此使用生成器, 如果您只需要打印段落 ID:

import re


def main():
    with open("data.txt") as f:  # Using context manager to close resource
        for line in f:
            # and here just catch the ID
            match = re.match("<P ID=(\d+)>", line)
            if match:
                print("Current paragraph Number: {}".format(match.group(1)))

main()

这将产生相同的结果,而不会将整个 5 GB 加载到内存中。

【讨论】:

    【解决方案2】:

    一种可能的解决方案是在使用NLTK 处理后将您的输入传递给BeautifulSoup

    from bs4 import BeautifulSoup as soup
    results = [i['id'] for i in soup(content, 'html.parser').find_all('p')]
    

    输出:

    ['912', '5', '291', '621', '5', '1']
    

    BeautifulSoup 使您能够使用soup.contents 访问段落内容:

    for i in soup(content, 'html.parser').find_all('p'):
       print(i.contents)
    

    输出:

    ['\nbird\ndog\ndog\ndog\n']
    ['\naardvark\nbird\nbird\ncat\negret\n']
    ['\naardvark\naardvark\naardvark\naardvark\naardvark\nbird\ndog\nfish\nfish\nfish\n']
    ['\naardvark\naardvark\nbird\ndog\nfish\nfish\nfish\n']
    ['\nbird\negret\negret\n']
    ['\nbird\n']
    

    【讨论】:

    • 感谢您的建议。我从未使用过BeautifulSoup,所以很高兴知道这一点。正如我提到的,我如何在我的段落循环中使用它(真正的程序需要循环遍历段落来做一些文本解析和其他事情)
    • @JerryM。请参阅我最近的编辑。 BeautifulSoup 使您能够利用 soup.contents 属性访问标签下的所有子值。
    • 谢谢,我会试试看能否在我发布的 for 循环格式中使用它并回复您。
    【解决方案3】:

    在 findall() 搜索中使用 r'(?s)&lt;P\s*ID\s*=\s*(\d+)\s*&gt;(.*?)&lt;/P\s*&gt;'
    ID 在捕获组 1 中,Content 在捕获组 2 中。

    例子

    >>> input = """
    ... <P ID=912>
    ... bird
    ... dog
    ... dog
    ... dog
    ... </P>
    ...
    ... <P ID=5>
    ... aardvark
    ... bird
    ... bird
    ... cat
    ... egret
    ... </P>
    ...
    ... <P ID=291>
    ... aardvark
    ... aardvark
    ... aardvark
    ... aardvark
    ... aardvark
    ... bird
    ... dog
    ... fish
    ... fish
    ... fish
    ... </P>
    ...
    ... <P ID=621>
    ... aardvark
    ... aardvark
    ... bird
    ... dog
    ... fish
    ... fish
    ... fish
    ... </P>
    ...
    ... <P ID=5>
    ... bird
    ... egret
    ... egret
    ... </P>
    ...
    ... <P ID=1>
    ... bird
    ... </P>
    ... """
    >>>
    >>> import re
    >>> p = re.compile(r'(?s)<P\s*ID\s*=\s*(\d+)\s*>(.*?)</P\s*>')
    >>>
    >>> ids = p.findall(input)
    >>>
    >>> i = 0
    >>> ids_len = len(ids)
    >>>
    >>> while ( i < ids_len ):
    ...     print(ids[i])     # The ID
    ...     print(ids[i+1])   # The Content
    ...     i += 2
    ...
    ('912', '\nbird\ndog\ndog\ndog\n')
    ('5', '\naardvark\nbird\nbird\ncat\negret\n')
    ('291', '\naardvark\naardvark\naardvark\naardvark\naardvark\nbird\ndog\nfish\nfish\nfish\n')
    ('621', '\naardvark\naardvark\nbird\ndog\nfish\nfish\nfish\n')
    ('5', '\nbird\negret\negret\n')
    ('1', '\nbird\n')
    >>>
    

    【讨论】:

    • 你能把例子贴出来吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 1970-01-01
    • 1970-01-01
    • 2015-12-25
    • 2019-05-13
    相关资源
    最近更新 更多