如何更快地遍历此文本文件?

时间:2017-11-25 20:43:37

标签: python parsing dictionary

我有一个包含这种格式的许多部分的文件:

async

该文件可以长达数十万行。每个部分的属性和字段数可以不同。我想构建一些字典来保存这些值。我有一个单独的字典,它包含所有可能的“属性”值。

export class AbstractComponent {
  user$;
  constructor() {
    // your real http request should be here
    this.user$ = Observable.of({name: 'John Doe'});
  }
}

@Component({
  selector: 'my-app',
  template: `
    <div>Hello {{(user$ | async).name}}</div>
  `,
})
export class App extends AbstractComponent {
  constructor() {
    super();
  }
}

我的问题是匹配所有字段值的while循环明显慢于代码的其余部分:如果我删除while循环,则根据cPro​​file显示0.5s vs 2.2s。我想知道我能做些什么来加速它。

1 个答案:

答案 0 :(得分:2)

当您需要花哨的模式匹配时,正则表达式很棒,但是当您不需要它时,使用str方法解析文本会更快。下面是一些代码,用于比较使用正则表达式进行字段解析的时间与使用str.split进行字段解析的时间。

首先,我创建一些假的测试数据,存储在rows列表中。这样做使我的演示代码比从文件中读取数据更简单,但更重要的是,它消除了文件读取的开销,因此我们可以更准确地比较解析速度。

顺便说一句,你应该将sectionNameMatch.group(1)保存在字段解析循环之外,而不是必须在每个字段行上进行调用。

首先,我将说明我的代码正确解析数据。 :)

import re
from pprint import pprint
from time import perf_counter

# Make some test data
num = 10
rows = []
for i in range(1, num):
    j = 100 * i
    rows.append(' field_{:03} {}:{} some_text here ;'.format(i, j, j - 50))
rows.append('};')
print('\n'.join(rows))

# Select whether to use regex to do the parsing or `str.split`
use_regex = True
print('Testing {}'.format(('str.split', 'regex')[use_regex]))

fh = iter(rows)
fieldMap = {}

nextLine = next(fh)
start = perf_counter()
if use_regex:
    while not "};" in nextLine: 
        fieldMatch = re.search(r'(\S+)\s+(\d+):(\d+)', nextLine)
        if fieldMatch:
            fieldMap[fieldMatch.group(1)] = [fieldMatch.group(2), fieldMatch.group(3)]
        nextLine = next(fh)
else:
    while not "};" in nextLine: 
        if nextLine:
            data = nextLine.split(maxsplit=2)
            fieldMap[data[0]] = data[1].split(':')
        nextLine = next(fh)

print('time: {:.6f}'.format(perf_counter() - start))
pprint(fieldMap)

<强>输出

 field_001 100:50 some_text here ;
 field_002 200:150 some_text here ;
 field_003 300:250 some_text here ;
 field_004 400:350 some_text here ;
 field_005 500:450 some_text here ;
 field_006 600:550 some_text here ;
 field_007 700:650 some_text here ;
 field_008 800:750 some_text here ;
 field_009 900:850 some_text here ;
};
Testing regex
time: 0.001946
{'field_001': ['100', '50'],
 'field_002': ['200', '150'],
 'field_003': ['300', '250'],
 'field_004': ['400', '350'],
 'field_005': ['500', '450'],
 'field_006': ['600', '550'],
 'field_007': ['700', '650'],
 'field_008': ['800', '750'],
 'field_009': ['900', '850']}

这是use_regex = False的输出;我不打算重新打印输入数据。

Testing str.split
time: 0.000100
{'field_001': ['100', '50'],
 'field_002': ['200', '150'],
 'field_003': ['300', '250'],
 'field_004': ['400', '350'],
 'field_005': ['500', '450'],
 'field_006': ['600', '550'],
 'field_007': ['700', '650'],
 'field_008': ['800', '750'],
 'field_009': ['900', '850']}

现在进行真正的测试。我将设置num = 200000并注释掉打印输入和输出的行。输出数据。

Testing regex
time: 3.640832

Testing str.split
time: 2.480094

正如您所看到的,正则表达式版本的速度慢了约50%。

这些时间是在运行Python 3.6.0的古老的2GHz 32位机器上获得的,因此您的速度可能会有所不同。 ;)如果你的Python没有time.perf_counter,你可以改用time.time