python 查找并匹配精确字符串
我该如何将一个.csv文件中的某一列字符串与一系列定义好的数据类型进行匹配呢?
这些数据类型的列表是:
Datatype = ["M", "B", "E", "A", "DF", "DW", "DL", "DT", "XTEXT", "MDEDATA"]
我想用匹配到的类型去字典里查找一个值。
有效的部分
当我的代码在输入中找到像DW1
这样的内容时(下面有例子),它会在输出文件中写入DW:5
;而当找到DT34
时,它会写入DT:7
。这一切都运行得很好。
无效的部分
但问题是,每当我的代码遇到XTEXT
时,它首先会把它匹配到E: 2
(因为E
在XTEXT
中),然后再匹配到下一行的XTEXT: 4105
。结果,输出文件中对应的行显示的是2
而不是4105
。类似的情况也发生在MDEDATA
上,它被解析为A:3
。
我尝试使用正则表达式来去掉输入文件中相关列的数字(这行在上面的代码中被注释掉了),像这样:
if (Datatype[n] == re.sub('[1234567890\n]', '', line.split(";")[1])):
# ...
但这在遇到像X256DATA
这样的字符串时会造成问题。
另一个问题是,当前生成的输出文件在第一列显示abc;DW1
,第二列显示5
,但我希望第一列是abc
,第二列是DW1
,第三列是5
!
我该如何解决这些问题?任何帮助都非常感谢。
CSV示例
输入:
1 abc DW1
2 uz5 XTEXT
当前输出:
1 abc DW1 5
2 uz5 XTEXT 4105
TXT示例
输入:
abc;DW1\n
uz5;XTEXT\n
当前输出:
abc;DW1,5\n
uz5;XTEXT,4105\n
期望输出
abc;DW1;5\n
uz5;XTEXT;4105\n
3 个回答
正如itsjeyd所建议的,
re.sub('^[0-9]+', '', x) or re.sub('[0-9]+$', '', x) does the trick!
好的,这里有一个基于你代码的解决方案,应该能适用于你的.txt
文件格式:
import csv
# Define data_type / dict1 / dict2:
data_type = [
"M", "E", "B", "A", "DF", "DW", "DL", "DT", "PF", "PW", "PL", "PT",
"XTEXT", "MDEDATA", "X8DATA", "X16DATA", "X32DATA", "X64DATA",
"X128DATA", "X256DATA", "X512DATA", "X1024DATA", "X2048DATA",
"X4096DATA", "X8912DATA"]
dict1 = {
"M": 1, "E": 2, "A": 3, "DF": 4, "DW": 5, "DL": 6, "DT": 7, "PF": 8,
"PW": 9, "B": 10, "PL": 11, "PT": 12, "XTEXT": 4105, "MDEDATA": 4110,
"X8DATA": 10000, "X16DATA": 10001, "X32DATA": 10002, "X64DATA": 10003,
"X128DATA": 10004, "X256DATA": 10005, "X512DATA": 10006,
"X1024DATA": 10007, "X2048DATA": 10008, "X4096DATA": 10009,
"X8912DATA": 10010}
dict2 = {
"M": "B", "E": "B", "A": "B", "DF": ">f","PF": ">f", "DW": ">h",
"PW": ">h", "DL": ">l", "PL": ">l", "DT": "String", "PT": "String",
"B": "B", "XTEXT": "XTEXT", "MDEDATA": "MDEDATA", "X8DATA": "X8DATA",
"X16DATA": "X16DATA", "X32DATA": "X32DATA", "X64DATA": "X64DATA",
"X128DATA": "X128DATA", "X256DATA": "X256DATA", "X512DATA": "X512DATA",
"X1024DATA": "X1024DATA", "X2048DATA": "X2048DATA",
"X4096DATA": "X4096DATA", "X8912DATA": "X8912DATA"}
# Obtain writer for output file:
source = 'GSV.txt'
dest = open('GSV_copy.txt', 'w')
# Process data:
import re
source_lines = open(source).readlines()
for line in source_lines:
x = line.split(';')[1]
icon_lletter = ''
icon_lnummer = 0
python_letter = ''
for t in data_type:
if x.startswith(t): # Alternative using re: "if re.match(t, x)"
icon_lletter = t
break
if (icon_lletter not in dict1):
print "Entry (%s) in Dictionary1 is not available" % (icon_lletter)
else:
icon_lnummer = dict1[icon_lletter]
if (icon_lletter not in dict2):
print "Entry (%s) in Dictionary2 is not available" % (icon_lletter)
else:
python_letter = dict2[icon_lletter]
print "Converted the GVR datatype to python datatype is %s : %s : %s" \
% (icon_lletter, python_letter, icon_lnummer)
# Write line to output file:
dest.write(';'.join([line.strip('\n'), str(icon_lnummer) + '\n']))
dest.close()
请注意:
这个解决方案是我在尽量保持你原始实现的基础上来解决你的问题。其实还有其他方法可以达到你的目标,可能会更符合Python的风格、更高效或者更简洁。
因为你的输入和输出文件的列数不一样,格式也不同,所以你最终可能需要把代码改成一个(或多个)函数,这样可以把不同的部分(文件类型和要检查的列)作为参数传入。
编辑:
在进一步研究这个问题时,我发现dest
中的输出有点混乱。(我之前没注意到这一点 :)) 我已经修改了代码,现在可以生成你想要的确切输出。
另一个编辑(基于评论中的讨论):
关于在输入文件中匹配数据类型与定义的data_type
列表的问题:如果你输入文件中的DT
总是有你不想考虑的数字在开头或结尾,你可以使用
re.sub('^[0-9]+', '', x)
或者
re.sub('[0-9]+$', '', x)
来去掉它们。
正常情况下,查字典是要完全匹配键的。如果你得到多个匹配,那说明你在做其他事情。
>>> dict1 = {"M":1, "E":2, "A":3, "DF":4, "DW":5, "DL":6, "DT":7, "B":10, "XTEXT":4105, "MDEDATA":4110}
>>> dict1["XTEXT"]
4105
从更新的问题来看,你其实并不是在找完全匹配的内容,因为文件中的 DW1
应该和 Datatype
中的 DW
匹配。如果你想检查字符串的开头是否匹配,可以使用 str.startswith
:
>>> "DW1".startswith("DW")
True
注意,你必须先检查 MDEDATA
再检查 M
,这样才能避免错误匹配。一般来说,先检查较长的匹配,再检查较短的匹配。