2015-08-28 35 views
3

这是我的样本数据在python获得第一和第二管之间的数据

78|Indonesia|Pamela|Reid|[email protected]|147.3.67.193 

我想要得到的结果作为

Indonesia 

目前我使用的字符串分割和访问值。但我想使用它的正则表达式。

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

我想用正则表达式,而不是分裂,因为我觉得正则表达式是更有效的。我希望这样做尽可能高效的原因是源文件是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 

我只是困惑上的答案我现在用:(

我只是想让这段代码变快,就是这样。

+0

你可以逐行分析是正确的话,根本不是知识 – The6thSense

+0

关系按如果有一个管道将总是存在一个以上或可以在任何地方出现管道? –

+0

@PadraicCunningham我不明白你在说什么 – v1shnu

回答

2

分裂并检查长度仍然可以比一个正则表达式更快:

In [24]: s = "78|Indonesia|Pamela|Reid|[email protected]|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 [email protected] 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 

可以剃略偏关:

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

上匹配和不匹配的行的一些定时通过创建一个本地参考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]”除此之外,除非你真的想要一组所有的名字,我会从代码中删除它。

应用相同的逻辑来划分:

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 
+0

你能编辑你的答案来匹配我的代码吗? – v1shnu

+0

当我回到我的比赛时我会编辑。 –

+0

@ViChU,总是有相同数量的管道?这将成为什么最好的方法的一个重要因素 –

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(回答问题的用户回答了上面的问题)进行了测试,它的效率比正则表达式要高。

0

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

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

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

性能正则表达式快速失败,非贪婪匹配和锚定非常重要。

+1

OP所说的子句可能是空的,所以你可能需要'd *'作为第一部分 –

+0

你绝对正确。我认为OP是指只有第二个条款可能是空的。固定。 – Andrew

0

只需使用此正则表达式获取第一个单词。

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

这也考虑了第一个元素。 – v1shnu

+0

列印第一组。 –

0

这会给你第一和第二管之间的事:

re.search(r'(?<=\|)[^|]*',s).group() 

re.search(模式,字符串,旗帜= 0) 扫描通过串寻找 第一位置正则表达式模式产生 匹配.....

0

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

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

DEMO

5

下面是关于Python 3.4.3 有意义答案的性能:

In [4]: timeit.timeit('s.split("|", 2)[1]', 's = "78|Indonesia|Pamela|Reid|[email protected]|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|[email protected]|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|[email protected]|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|[email protected]|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 
+0

如果没有管道,该怎么办? –

+1

@AvinashRaj:然后数据文件被破坏,所以如果程序产生异常,这是可以接受的。根据OP,他们只需要从第二列中提取数据,所以假设总会有(至少)两列是合理的。 –

+0

@AvinashRaj查看新增的部分。 –