【问题标题】:Python - All the lines and line numbers in which string occurs in the input filePython - 输入文件中出现字符串的所有行和行号
【发布时间】:2018-10-27 13:25:18
【问题描述】:

我想打印输入文件中出现字符串的所有行以及行号。到目前为止,我编写了如下所示的代码。它正在工作,但不是我想要的方式:

def index(filepath, keyword):

    with open(filepath) as f:
        for lineno, line in enumerate(f, start=1):
            matches = [k for k in keyword if k in line]
            if matches:
                result = "{:<15} {}".format(','.join(matches), lineno)
                print(result)
                print (line)

index('deneme.txt', ['elma'])

输出如下:

elma            15
Sogan+Noun ,+Punc domates+Noun ,+Punc patates+Noun ,+Punc elma+Noun ve+Conj turunçgil+Noun+A3pl ihracat+Noun+P3sg+Dat devlet+Noun destek+Noun+P3sg ver+Verb+Pass+Prog2+Cop .+Punc  

到目前为止一切顺利,但是当我输入像 "Sog" 这样的关键字时,它也会找到 Sogan 但我不希望这样,我只想检查空格之间的标记。我想我需要为此编写正则表达式,我得到了一个,但我现在不知道如何将该正则表达式添加到这段代码中。

r'[\w+]+'

【问题讨论】:

    标签: python regex python-3.x file keyword


    【解决方案1】:

    您可能想要使用单词边界标记\b。这是\w\W 之间转换的空匹配。如果您希望关键字是文字字符串,则必须先escape 他们。您可以使用| 将所有内容组合成一个正则表达式:

    pattern = re.compile(r'\b(' + '|'.join(map(re.escape, keyword)) + r')\b')
    

    pattern = re.compile(r'\b(?' + '|'.join(re.escape(k) for k in keyword) + r')\b')
    

    现在计算匹配更容易了,因为您可以使用finditer 而不是自己理解:

    matches = pattern.finditer(line)
    

    由于每个匹配项都包含在一个组中,因此打印并不困难:

    result = "{:<15} {}".format(','.join(m.group() for m in matches), lineno)
    

    result = "{:<15} {}".format(','.join(map(re.Match.group(), matches)), lineno)
    

    当然,别忘了

    import re
    

    角落案例

    如果您的关键字是彼此具有相同前缀的子集,请确保较长的关键字在前。例如,如果您有

    keyword = ['foo', 'foobar']
    

    正则表达式将是

    \b(foo|foobar)\b
    

    当您遇到包含foobar 的行时,foo 将成功匹配它,然后匹配失败\b'. This is documented behavior of|`。解决方案是在构造表达式之前通过减少长度对所有关键字进行预排序:

    keywords.sort(key=len, reversed=True)
    

    或者,如果非列表输入是可能的:

    keywords = sorted(keywords, key=len, reversed=True)
    

    如果你不喜欢这个顺序,你可以在匹配后以其他顺序打印它们。

    【讨论】:

    • 您的模式字段出错,我认为正则表达式有一些错误。
    【解决方案2】:

    您可以使用以下正则表达式:

    import re
    
    lines = [
        'Sogan+Noun ,+Punc domates+Noun ,+Punc patates+Noun ,+Punc elma+Noun ve+Conj turunçgil+Noun+A3pl ihracat+Noun+P3sg+Dat devlet+Noun destek+Noun+P3sg ver+Verb+Pass+Prog2+Cop .+Punc',
        'Sog+Noun ,+Punc domates+Noun ,+Punc patates+Noun ,+Punc elma+Noun ve+Conj turunçgil+Noun+A3pl ihracat+Noun+P3sg+Dat devlet+Noun destek+Noun+P3sg ver+Verb+Pass+Prog2+Cop .+Punc',
    ]
    
    keywords = ['Sog']
    pattern = re.compile('(\w+)\+')
    
    for lineno, line in enumerate(lines):
        words = set(m.group(1) for m in pattern.finditer(line))  # convert to set for efficiency
        matches = [keyword for keyword in keywords if keyword in words]
        if matches:
            result = "{:<15} {}".format(','.join(matches), lineno)
            print(result)
            print(line)
    

    输出

    Sog             1
    Sog+Noun ,+Punc domates+Noun ,+Punc patates+Noun ,+Punc elma+Noun ve+Conj turunçgil+Noun+A3pl ihracat+Noun+P3sg+Dat devlet+Noun destek+Noun+P3sg ver+Verb+Pass+Prog2+Cop .+Punc
    

    说明

    模式'(\w+)\+' 任意一组字母后跟+ 字符,+ 是特殊字符,因此您需要对其进行转义才能匹配。然后使用 group 提取匹配组,(即字母组)。

    进一步

    1. 正则表达式syntax

    【讨论】:

      【解决方案3】:

      问题:像“Sog”这样的关键字它也能找到 Sogan ...我只想要空格之间的标记。 ...我如何将该正则表达式添加到此代码中。

      用您的keywords 构建一个regex,使用or | 分隔多个keywords

      例如:

      import re
      
      def index(lines, keyword):
          rc = re.compile(".*?(({})\+.+?\s)".format(keyword))
      
          for i, line in enumerate(lines):
              match = rc.match(line)
              if match:
                  print("lines[{}] match:{}\n{}".format(i, match.groups(), line))
      
      if __name__ == "__main__":
          lines = [
          'Sogan+Noun ,+Punc domates+Noun ,+Punc patates+Noun ,+Punc elmaro+Noun ve+Conj ... (omitted for brevity)',
          'Sog+Noun ,+Punc domates+Noun ,+Punc patates+Noun ,+Punc elma+Noun ve+Conj ... (omitted for brevity)',
      ]
          index(lines, 'elma')
          index(lines, 'Sog|elma')
      

      输出

      lines[1] match:('elma+Noun ', 'elma')
      Sog+Noun ,+Punc domates+Noun ,+Punc patates+Noun ,+Punc elma+Noun ve+Conj ... (omitted for brevity)
      lines[1] match:('Sog+Noun ', 'Sog')
      Sog+Noun ,+Punc domates+Noun ,+Punc patates+Noun ,+Punc elma+Noun ve+Conj ... (omitted for brevity)
      

      用 Python 测试:3.5

      【讨论】:

        猜你喜欢
        • 2014-07-21
        • 2019-02-18
        • 2012-12-06
        • 2011-09-03
        • 2015-08-19
        • 2021-07-23
        • 2014-03-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多