在python中获取第一个和第二个管道之间的数据

时间:2015-08-28 13:22:05

标签: python regex

这是我的样本数据

78|Indonesia|Pamela|Reid|preid25@gravatar.com|147.3.67.193

我希望得到结果

Indonesia

目前我在字符串上使用split并访问该值。但是我想用正则表达式。

需要注意的一些条件: 数据可能为空 数据不包含管道(|)

我想使用正则表达式而不是拆分,因为我认为正则表达式更有效。我希望它尽可能高效的原因是源文件 70gb

修改

这是我将使用此

的完整代码
def main(argv):
    mylist = set();
    input_file = open("test.txt", 'r')

    for row in input_file:
        rowsplit = row.split("|");

        if rowsplit[1] !='':
            if rowsplit[1] in mylist:
                filename= "bby_"+rowsplit[1]+".dat";
                existingFile=open(filename,'a')
                existingFile.write(row);
                existingFile.close()
            else:
                mylist.add(rowsplit[1])
                filename= "bby_"+rowsplit[1]+".dat";
                newFile = open(filename,'a')
                newFile.write(row);
                newFile.close();
        else:
            print "Empty"
    print mylist

我对我现在应该使用的答案感到困惑:(

我只是希望这段代码很快。多数民众赞成。

7 个答案:

答案 0 :(得分:5)

以下是Python 3.4.3上有意义的答案的表现:

In [4]: timeit.timeit('s.split("|", 2)[1]', 's = "78|Indonesia|Pamela|Reid|preid25@gravatar.com|147.3.67.193"')
Out[4]: 0.43930888699833304

In [10]: timeit.timeit('re.search(r"^[^a-zA-Z]*([a-zA-Z]+)", s).group(1)', 's = "78|Indonesia|Pamela|Reid|preid25@gravatar.com|147.3.67.193"; import re')
Out[10]: 1.234878903022036

In [16]: timeit.timeit('re.search("^\d*\|(\w+?)?\|", s).group(1)', 's = "78|Indonesia|Pamela|Reid|preid25@gravatar.com|147.3.67.193"; import re')
Out[16]: 1.8305770770530216

如果没有管道:

In [24]: timeit.timeit('s.split("|", 2)[1] if "|" in s else None', 's = "78|Indonesia|Pamela|Reid|preid25@gravatar.com|147.3.67.193"')
Out[24]: 0.494665392965544

In [25]: timeit.timeit('s.split("|", 2)[1] if "|" in s else None', 's =  ""')
Out[25]: 0.04492994397878647

答案 1 :(得分:2)

拆分和检查长度可能仍然比正则表达式更快:

for line in f:
    spl = line.split("|",2)
    if len(spl) > 2:
        print(spl[1])
       ....

匹配和不匹配行的一些时间:

In [24]: s = "78|Indonesia|Pamela|Reid|preid25@gravatar.com|147.3.67.193"

In [25]: %%timeit                                                        
    spl = s.split("|",2)
    if len(spl) > 2:
        pass
   ....: 
1000000 loops, best of 3: 413 ns per loop

In [26]: r = re.compile(r'(?<=\|)[^|]*')

In [27]: timeit r.search(s)                                            
1000000 loops, best of 3: 452 ns per loop

In [28]: s = "78 Indonesia Pamela Reid preid25@gravatar.com 147.3.67.193"

In [29]: timeit r.search(s)
1000000 loops, best of 3: 1.66 µs per loop

In [30]: %%timeit                       
    spl = s.split("|",2)
    if len(spl) > 2:
        pass
   ....: 
1000000 loops, best of 3: 342 ns per loop

您可以通过创建对str.split的本地引用来减少更多:

_spl = str.split
for line in f:
    spl = _spl(s,"|",2)
    if len(spl) > 2:
      .....

由于每行中的管道数始终相同:

def main(argv):
    seen = set() # only use if you actually need  a set of all names
    with open("test.txt", 'r') as infile:
        r = csv.reader(infile, delimiter="|")
        for row in r:
            v = row[1]
            if v:
                filename = "bby_" + v + ".dat"
                existingFile = open(filename, 'a')
                existingFile.write(row)
                existingFile.close()
                seen.add(v)
            else:
                print "Empty"

if / else似乎是多余的,因为你要附加到文件中,如果你想保留一组行[1]&s 39,因为你可以每次只添加到该集合,除非你实际上想要一组我将从代码中删除它的所有名称。

应用相同的逻辑进行拆分:

def main(argv):
    seen = set()
    with open("test.txt", 'r') as infile:
        _spl = str.split
        for row in infile:
            v = _spl(row,"|",2)[1]
            if v:
                filename = "bby_" + v + ".dat"
                existingFile = open(filename, 'a')
                existingFile.write(row)
                existingFile.close()
                seen.add(v)
            else:
                print "Empty"

导致大量开销的是不断打开和写入,但除非你能将所有行存储在内存中,否则没有简单的方法来解决它。

就阅读而言,在一个包含一千万行的文件中,只需拆分两次就会超过csv阅读器:

In [15]: with open("in.txt") as f:
   ....:     print(sum(1 for _ in f))
   ....: 
10000000

In [16]: paste
def main(argv):
    with open(argv, 'r') as infile:
        for row in infile:
            v = row.split("|", 2)[1]
            if v:
                pass
## -- End pasted text --

In [17]: paste
def main_r(argv):
    with open(argv, 'r') as infile:
        r = csv.reader(infile, delimiter="|")
        for row in r:
            if row[1]:
                pass

## -- End pasted text --

In [18]: timeit main("in.txt")
1 loops, best of 3: 3.85 s per loop

In [19]: timeit main_r("in.txt")
1 loops, best of 3: 6.62 s per loop

答案 2 :(得分:0)

我认为您可以在Python: Split string by list of separators

找到答案
def split(txt, seps):
    default_sep = seps[0]

    # we skip seps[0] because that's the default seperator
    for sep in seps[1:]:
        txt = txt.replace(sep, default_sep)

    return [i.strip() for i in txt.split(default_sep)]

Joschua(回答了与上述相关的问题的用户)进行了测试,并且正则表达式效率更高。

答案 3 :(得分:0)

这很简单:如果你知道第一个句子总是一个数字(或空的),你可以锚定到前面。

^\d*\|(\w+?)?\|

这将匹配行前面的0或更多数字,后跟一个文字|字符,后跟第1条,其中包含一个非贪婪匹配的单词(没有空格),或者没有如果它不存在,则后跟一个文字|字符。

性能正则表达式是关于快速失败,非贪婪的匹配和锚点是至关重要的。

答案 4 :(得分:0)

使用此正则表达式抓住第一个单词。

re.search(r'^[^a-zA-Z]*([a-zA-Z]+)', S).group(1)

答案 5 :(得分:0)

这将为您提供第一和第二管道之间的东西:

app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
  

re.search(pattern,string,flags = 0)   扫描字符串寻找   正则表达式模式生成的第一个位置   匹配.....

答案 6 :(得分:0)

如果总是有相同的nuber管道,你可以使用正则表达式:

[^|]+(?=(?:\|[^|]+\|?){4}$)

DEMO