【问题标题】:python grep multiple words in logcatpython grep logcat中的多个单词
【发布时间】:2019-01-18 04:21:23
【问题描述】:

Shell 脚本:

logcat | grep -E "one|two|three"

Python 代码:

key_words = [ "one", "two", "three"]
log_lines = os.popen("logcat");

for log_line in log_lines:
   for keyword in key_words:
        if keyword in log_line:
             print log_line

上面的python代码有什么优化吗?

【问题讨论】:

  • 如果一行包含多个关键字,是否要打印两次/三次?
  • logcat 可以直接做logcat -e <regex>,不确定它是否支持像| 这样的扩展正则表达式语法。此外,具有多个匹配项的行只会显示一次。
  • os.popen() 曾经带有一个又大又丑的警告,说它已被弃用,但看起来警告现在已经消失了。我猜他们无法杀死它,所以他们在 subprocess 之上重新实现了它,这正是我要推荐的。
  • 如果您使用的是 Python 2,os.popen() 仍然是您应该避免的事情。 (但是 Python 2 现在是你应该非常避免的事情。考虑尽快迁移到 Python 3。)

标签: python logcat


【解决方案1】:

要在您的 grep 命令中模拟确切的模式,请执行

import re

pattern = re.compile('|'.join(key_words))

for log_line in log_lines:
    if pattern.search(log_line):
        print log_line

如果你想允许特殊字符,你必须转义它们:

pattern = re.compile('|'.join(re.escape(word) for word in key_words))

您可以想象,在这种情况下使用正则表达式有点矫枉过正。相反,您可以进行直接搜索。您可以使用any 来帮助搜索,因为它会短路。

for log_line in log_lines:
    if any(word in log_line for word in key_words):
        print log_line

这将对每个关键字的整行执行线性搜索。如果关键字是实际单词,则可以提高效率,特别是因为您已经为关键字设置了一组:

for log_line in log_lines:
    if keywords.intersection(set(log_line.split()):
        print log_line

【讨论】:

  • any 总是被低估:-)
【解决方案2】:

您提出的解决方案打印具有多个关键字的行的频率与它们拥有的关键字数量一样多,这可能是您想要避免的。此外,如果关键字作为另一个单词的一部分出现,它也会出现(尽管这与 grep 行为匹配)。

一些解决方案:

import os

key_words = {"one", "two", "three"}
log_lines = ['This has a one and a two', 'Some ones', 'This one has neither, oh it does', 'This does not', 'A three']

# fixing the repetition    
for log_line in log_lines:
   for keyword in key_words:
        if keyword in log_line:
             print(log_line)
             break

# fixing the repetition and partial matches
for log_line in log_lines:
    for word in log_line.split():
        if word in key_words:
            print(log_line)
            break

# single line solution
print([log_line for log_line in log_lines if key_words & set(log_line.split()) != set()])

# single line solution with partial matches
print([log_line for log_line in log_lines if any(key_word in log_line for key_word in key_words)])

【讨论】:

  • 请注意,key_words 在我的示例中是一个集合,而不是一个列表,因此是 {}
【解决方案3】:

您好,您可以使用正则表达式并尝试此方案。您还可以根据您的要求更改正则表达式检查以下示例:

import re

key_words = [ "one", "two", "three"]
regex  = "|".join(key_words)
log_lines = open("logcat", 'r')
lines = log_lines.readlines()
print filter(lambda x : re.search(regex,x), lines)

log_lines.close()

【讨论】:

    【解决方案4】:

    第一个优化实际上是在找到匹配项后立即break

    key_words = [ "one", "two", "three"]
    log_lines = os.popen("logcat");
    
    for log_line in log_lines:
        for keyword in key_words:
            if keyword in log_line:
                print log_line
                break    # stop looking for keywords if you already found one
    

    一个更易读的解决方案是用正则表达式替换关键字循环检查。如果匹配,则打印该行:

    import re
    key_words = [ "one", "two", "three"]
    regex = re.compile('|'.join(key_words))    # one|two|three
    
    log_lines = os.popen("logcat");
    for log_line in log_lines:
        if regex.match(log_line):    # returns None if no match, an object if there is a match
            print log_line
    

    从性能的角度来看,不确定哪个会更快,但一个更具可读性。不过,结果中有一些警告。

    【讨论】:

    • 我确定您已经看到 os.popen 文档中的大警告框,上面写着不要使用这个?
    • @tripleee 是的,但这是 OP 在他们的代码中的内容,这并不是问题的一部分。你真的可以就主要问题发表评论吗?我认为这很重要。
    • 哦,看起来大错误警告实际上在 Python 3.7 中消失了。它现在使用subprocess.Popen 重新实现。我的错。
    • 这对于 Python 2.7 仍然是一个不好的警告,所以你的观点是有效的,特别是因为我认为这个例子是在 Python 2.x 中。感谢您的检查!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多