如何读取/提取超过20个空格的行? - unix / python

时间:2014-02-02 22:53:20

标签: python unix if-statement text-files yield

所需的任务是提取包含x个y出现次数的行。输入文本文件包含1,000,000行,每行50-200个字符。

在这种情况下,假设包含20个空格的行。有更多的pythonic方式吗?目前,我这样做:

import codecs

def readlinesmorethan20spaces(intxtfile):
    with codecs.open(intxtfile, 'r','utf8') as fin:
        for i in fin:
            if i.count(" ") > 20:
                yield i.strip()

for i in readlinesmorethan20spaces("in.txt"):
    print i

如果没有python但是使用unix命令怎么办呢?它甚至可能吗?

4 个答案:

答案 0 :(得分:4)

使用grep和sed的Unix方式:

grep -E '(\s[^\s]*){20,}' in.txt | sed 's/^\s*//;s/\s*$//'

第一个命令过滤具有20+个空格(甚至非连续)的行,然后第二个命令剥离前导和尾随空格。

这不是一种理想的方法,它可能比其他方法慢(awk也许),但它很简单。顺便说一句,我对本页提到的不同方法的性能比较感兴趣...

是的,几乎所有东西都可以用正则表达式解决! ;)

答案 1 :(得分:0)

列表组件通常更加pythonic。在您的上下文中,它看起来像这样:

import codecs, re

def readlinesmorethan20spaces(intxtfile):
    with codecs.open(intxtfile, 'r','utf8') as fin:
        return (i.strip() for i in fin if i.count(' ') > 20)

for i in readlinesmorethan20spaces("in.txt"):
    print i

在这种情况下,返回生成器与之前的yield语句类似。

如果您愿意,也可以将其作为一行进行,但我认为上述版本更具可读性:

read_lines = lambda fn: (i.strip() for i in codecs.open(fn, 'r', 'utf8') if i.count(' ') > 20)

unix方法不太直接,但这应该是完全可能的。开始可能是使用awk来计算每行中的字符。这是一个例子:

awk -v FS=""'{cnt=0;for (i=1;i<=NF;i++) if ($i==" ") cnt++; print cnt"\t"NR}' stores.dat

答案 2 :(得分:0)

我通常不会打扰发电机

import codecs
with codecs.open(intxtfile, 'r','utf8') as fin:
    for i in fin:
        if i.count(' ') <= 20:
            continue
        i = i.strip()
        ...

使用函数/生成器的一个优点是单元测试的细粒度组件。正如评论中所提到的那样 - 稍微移动一下会使生成器更容易测试,因为fin不需要是一个打开的文件 - 它同样可以是一个列表等。

import codecs

def readlinesmorethan20spaces(fin):
    for i in fin:
        if i.count(" ") > 20:
            yield i.strip()

with codecs.open(intxtfile, 'r','utf8') as fin:
    for i in readlinesmorethan20spaces(fin):
        print i

答案 3 :(得分:0)

使用高性能容器collections.Counter的其他方式:

import codecs
import collections

def readlinesmorethan20spaces(intxtfile):
    with codecs.open(intxtfile, 'r','utf8') as fin:
        for line in fin:
            counter = collections.Counter(line)
            if counter[" "] > 20:
                yield line.strip()

for i in readlinesmorethan20spaces("in.txt"):
    print i