【问题标题】:Extracting text from string using Regex使用正则表达式从字符串中提取文本
【发布时间】:2018-08-17 19:45:57
【问题描述】:

我有一个很大的字符串。该字符串中有许多段落。每个段落都以标题开头并遵循特定模式。

例子:

== Title1 == // Paragraph starts ............. ............. // Some texts ............. End of Paragraph ===Title2 === // Paragraph starts ............. ............. // Some texts .............

标题的模式是:

1.) 新段落 title 以等于 ( = ) 开头,后面可以跟任意数量的 =。

2.) 在 = 之后,可以有一个空格(虽然不是必需的),然后是文本。

3.) 文本完成后,又可以有一个空格(不是必需的),然后是任意数量的等于(=)。

4.) 现在段落开始。我必须提取文本,直到遇到类似的模式。

谁能帮助我如何用正则表达式做到这一点? TIA

【问题讨论】:

标签: python regex


【解决方案1】:

你可以使用

re.findall(r'(?m)^=+[^\S\r\n]*(.*?)[^\S\r\n]*=+\s*(.*(?:\r?\n(?!=+.*?=).*)*)', s)

regex demo

详情

  • (?m)^ - 行首
  • =+ - 1 个或多个 = 字符
  • [^\S\r\n]* - 除 CR 和 LF 之外的零个或多个空白字符
  • (.*?) - 第 1 组:任何零个或多个字符(换行符除外),尽可能少
  • [^\S\r\n]* - 除 CR 和 LF 之外的零个或多个空白字符
  • =+ - 1 个或多个 = 字符
  • \s* - 0+ 个空格
  • (.*(?:\r?\n(?!==+.*?=).*)*) - 第 2 组:
    • .* - 任何零个或多个字符,除了换行符,尽可能多
    • (?:\r?\n(?!=+.*?=).*)* - 零个或多个序列
      • \r?\n(?!=+.*?=) - 一个可选的 CR,然后是 LF,后面不跟 1+ =s,然后是除换行符之外的任何字符,然后是 1+ =s
      • .* - 任何零个或多个字符,除了换行符,尽可能多

Python demo:

import re

rx = r"(?m)^=+[^\S\r\n]*(.*?)[^\S\r\n]*=+\s*(.*(?:\r?\n(?!=+.*?=).*)*)"
s = "== Title1 ==\n..........................\n.............\nEnd of Paragraph\n===Title2 ===\n.............\n.............\n............."
print(re.findall(rx, s))

输出:

[('Title1', '..........................\n.............\nEnd of Paragraph'), ('Title2', '.............\n.............\n.............')]

【讨论】:

    【解决方案2】:

    这可能有助于查找每个段落的标题和每个段落的行。

    text = """== Title1 == // Paragraph starts
    .............
    ............. // Some texts
    .............
    End of Paragraph
    ===Title2 === // Paragraph starts
    .............
    ............. // Some texts
    .............
    """
    import re
    
    reg = re.compile(r'(?:[=]+\s*\w+\s*[=]+)')
    
    for i in text.split('\n'):
        if re.search(reg, i):
            t = re.sub(r'=', '', i)
            print('Title:', t.strip())
        else:
            print('line:', i.strip())
    
     # Output like this
       Title: Title1  // Paragraph starts
       line: .............
       line: ............. // Some texts
       line: .............
       line: End of Paragraph
       Title: Title2  // Paragraph starts
       line: .............
       line: ............. // Some texts
       line: .............
       line: 
    

    【讨论】:

    • 非常感谢!我赞成你的答案,但我发现最后一个答案最合适,因此我接受了。
    【解决方案3】:

    你可以试试这个-

    x = "== Title1   ==="
    ptrn = "[=]{1,}[\s]{0,}[\w]+[\s]{0,}[=]{1,}"
    if re.search(ptrn, x):
        x = x.replace('=', '').strip()
    

    会给你Title1。或者假设您想要列表中的所有匹配标题,您可以这样做 -

    x = '== Title1   ===nansnsk fnasasklsanlkas lkaslkans \n== Title2 ==='
    titles = [i.replace('=', '').strip() for i in re.findall(ptrn, x)]
    # OP ['Title1', 'Title2']
    

    模式是-

    "^[=]{1,}[\s]{0,}[\w]+[\s]{0,}[=]{1,}"
    

    ^[=]{1,} - 在开头至少匹配一个等号

    [\s]{0,} - 匹配零到无限等号

    [\w]+ - 匹配 [a-zA-Z0-9_] 一次或多次

    之后,我们可以通过将= 替换为'' 并去掉空格来从中提取文本。您可以在regex101 尝试它,这在测试正则表达式时非常有用

    【讨论】:

    • 非常感谢!我赞成你的答案,但我发现最后一个答案最合适,因此我接受了。
    【解决方案4】:

    1.) 新段落标题以等于 (=) 开头,后面可以跟任意数量的 =。

    这可以用=+来表示。

    2.) 在 = 之后,可以有一个空格(虽然不是必需的),然后是文本。

    3.) 文本完成后,又可以有一个空格(不是必需的),然后是任意数量的等于(=)。

    所以标题的模式变成:=+[^=]+=+\n,这意味着,至少匹配一个=,然后是一些不包括=的文本,然后再匹配至少一个=

    捕捉这些模式之间的所有内容将为您提供所需的文本。

    在下面的模式中,整个匹配包含标题,第一组包含文本。

    所以最后,你的模式应该是:=+[^=]+=+\n([\w\W]+\n)(?==+[^=]+=+\n)

    Demo

    【讨论】:

    • 非常感谢!我赞成你的答案,但我发现最后一个答案最合适,因此我接受了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-17
    • 1970-01-01
    • 2013-02-24
    • 2014-08-25
    • 1970-01-01
    • 2015-12-11
    相关资源
    最近更新 更多