【问题标题】:Pythonic equivalent to Matlab's textscanPythonic 相当于 Matlab 的 textscan
【发布时间】:2018-07-18 05:41:50
【问题描述】:

有一些与此类似的问题,但我找不到确切的答案。

我有一个非常奇怪的文本文件,其内容如下:

field1=1; field2=2; field3=3; field1=4; field2=5; field3=6;

Matlab 的 textscan() 函数可以非常巧妙地处理这个问题,您可以这样做:

array = textscan(fid, 'field1=%d; field2=%d; field3=%d;'

你会得到一个单元格数组,其中每一列都包含相应的字段,文本被简单地忽略。

我想用 Python 重写处理这个文件的代码,但是 Numpy 的 loadtxt()genfromtxt() 似乎没有这种能力来忽略穿插有所需数字的文本?

有哪些 Python 方法可以去除文本并只取回字段?如果需要,我很乐意使用pandas 或其他库。谢谢!

编辑:This 问题被建议作为答案,但它仅提供与 textscan 基本用法相同的内容,不处理输入中不需要的文本。下面fromregex的答案是我需要的。

【问题讨论】:

  • @grshankar:我不会认为这个问题是重复的,因为这些答案指向 Numpy 的 loadtxt()genfromtxt(),由于要处理的数据结构,它们不符合 OP 的需求。我只是花时间阅读了 Matlab 的 textscan 的文档,我很确定没有简单的替代品。我能想到的最好的办法就是用正则表达式伪造它并将其作为答案。
  • 保持打开状态,除非找到更好的副本! OP 在他的问题中解决了这些答案的缺点。

标签: python matlab


【解决方案1】:

Numpy 的fromregex 功能与textscan 基本相同。它允许您基于正则表达式读取,其中组(由() 包围的部分)作为值。这适用于您的示例:

data = np.fromregex('temp.txt', r'field1=(\d+); field2=(\d+); field3=(\d+);', dtype='int')

您也可以使用loadtxt。有一个参数converters,它允许您提供将文本实际转换为数字的函数。你可以提供一个函数,你只需要提供一个函数来去掉不需要的文本。

所以在我的测试中这是可行的:

myconv = lambda x: int(x.split(b'=')[-1])
mycols = [0, 1, 2]
convdict = {i: myconv for i in mycols}
data = np.loadtxt('temp.txt', delimiter=';', usecols=mycols, converters=convdict)

myconv 是一个匿名函数,它接受一个值(比如'field1=1'),将其拆分为'=',符号(使['field1', '1']), takes the last result ('1'), the converts that to a float (1.`)。

mycols 只是您要保留的列数。由于每行末尾都有一个分隔符,因此这算作空列。所以我们排除了它。

convdict 是一个字典,其中每个键都是一个列号,每个值都是将该列转换为数字的函数。在这种情况下,它们都是相同的,但您可以根据需要自定义它们。

【讨论】:

  • 谢谢 - fromregex 非常接近 Matlab 语法,我认为它比 converters 方法更容易理解。我会选择fromregex
  • @StevenRumbalski:谢谢,已修复。
【解决方案2】:

Python 没有与 Matlab 的 textscan 完全相同的功能(edit: 但 numpy 有 fromregex。有关更多信息,请参阅 @TheBlackCat 的 answer。)

使用更复杂的格式,正则表达式可以完成这项工作。

import re

line_pat = re.compile(r'field1=(\d+); field2=(\d+); field3=(\d+);')
with open(filepath, 'r') as f:
    array = [[int(n) for n in line_pat.match(line).groups()] for line in f]

【讨论】:

    最近更新 更多