如何在Python中不使用正则匹配文本格式与字符串?
我正在读取一个文件,里面的每一行都是类似这样的格式:
[ 0 ] L= 9 (D) R= 14 (D) p= 0.0347222 e= 10 n= 34
我看到有一个Matlab代码可以用来读取这个文件,代码如下:
[I,L,Ls,R,Rs,p,e,n] = textread(f1,'[ %u ] L= %u%s R= %u%s p= %n e=%u n=%u')
我想用Python来读取这个文件。我唯一知道的就是正则表达式,但即使只读取这一行的一部分,结果也变成了这样:
re.compile('\s*\[\s*(?P<id>\d+)\s*\]\s*L\s*=\s*(?P<Lint>\d+)\s*\((?P<Ltype>[DG])\)\s*R\s*=\s*(?P<Rint>\d+)\s*')
看起来真糟糕!在Python中有没有更简单的方法来做到这一点呢?
4 个回答
2
在我看来,这段代码看起来差不多符合Python的风格:
line = "[ 0 ] L= 9 (D) R= 14 (D) p= 0.0347222 e= 10 n= 34"
parts = (None, int, None,
None, int, str,
None, int, str,
None, float,
None, int,
None, int)
[I,L,Ls,R,Rs,p,e,n] = [f(x) for f, x in zip(parts, line.split()) if f is not None]
print [I,L,Ls,R,Rs,p,e,n]
4
你可以通过使用转义和替换的方式,让正则表达式(regexp)更容易理解...
number = "([-+0-9.DdEe ]+)"
unit = r"\(([^)]+)\)"
t = "[X] L=XU R=XU p=X e=X n=X"
m = re.compile(re.escape(t).replace("X", number).replace("U", unit))
1
Pyparsing 是一种比难懂且不稳定的正则表达式处理器更好的选择。下面这个解析器示例可以处理你提到的格式,还能处理多余的空格和不同顺序的赋值表达式。就像你在正则表达式中使用命名组一样,pyparsing 也支持结果命名,这样你就可以通过字典或属性的方式来访问解析后的数据(比如 data['Lint'] 或 data.Lint)。
from pyparsing import Suppress, Word, nums, oneOf, Regex, ZeroOrMore, Optional
# define basic punctuation
EQ,LPAR,RPAR,LBRACK,RBRACK = map(Suppress,"=()[]")
# numeric values
integer = Word(nums).setParseAction(lambda t : int(t[0]))
real = Regex(r"[+-]?\d+\.\d*").setParseAction(lambda t : float(t[0]))
# id and assignment fields
idRef = LBRACK + integer("id") + RBRACK
typesep = LPAR + oneOf("D G") + RPAR
lExpr = 'L' + EQ + integer("Lint")
rExpr = 'R' + EQ + integer("Rint")
pExpr = 'p' + EQ + real("pFloat")
eExpr = 'e' + EQ + integer("Eint")
nExpr = 'n' + EQ + integer("Nint")
# accept assignments in any order, with or without leading (D) or (G)
assignment = lExpr | rExpr | pExpr | eExpr | nExpr
line = idRef + lExpr + ZeroOrMore(Optional(typesep) + assignment)
# test the parser
text = "[ 0 ] L= 9 (D) R= 14 (D) p= 0.0347222 e= 10 n= 34"
data = line.parseString(text)
print data.dump()
# prints
# [0, 'L', 9, 'D', 'R', 14, 'D', 'p', 0.034722200000000002, 'e', 10, 'n', 34]
# - Eint: 10
# - Lint: 9
# - Nint: 34
# - Rint: 14
# - id: 0
# - pFloat: 0.0347222
另外,解析动作会在解析时把字符串转换成整数或浮点数,这样之后的值就已经是可以直接使用的格式了。(在 pyparsing 中的思路是,当你解析这些表达式时,你知道由数字组成的单词 - 或者说 Word(nums)
- 可以安全地转换为整数,那为什么不在这个时候就进行转换呢?而不是先得到匹配的字符串,然后再重新处理这些字符串,试图判断哪些是整数、哪些是浮点数等等?)