我有一个程序需要将文本文件作为输入,并对每行代码执行一些操作。
在我可以对文本文件做任何事情之前,我需要确保每一行都匹配一个特定的格式,在这种情况下,它将是城市名称(可以是任何字符串,它不需要是真实的城市名称)后跟一个','后跟一个数字。
典型的线条如下所示:
towna,2.43
这就是我目前所拥有的,它在使程序功能方面起作用,但它不能验证数据是否正确,所以如果它的错误(并且它将不时)它会去给我一个错误。我读了一些关于re.match的内容,但我不明白如何使用它。
def read_file(fileName):
weatherFile = open(fileName)
for line in weatherFile:
stripped = line.replace(' ','')
pass #add data validation for file
town, rain = stripped.split(",")
if checkIfExists(town):
dataList.append({"city":town, "average_rainfall":float(rain.rstrip())})
else:
print("It looks like {0} is on the list twice. Please ensure all towns in {1} only appear once and try again." .format(town, fileName))
break
答案 0 :(得分:1)
在我回答之前,我必须指出在验证开始之前你正在弄乱数据。
如果用户输入'Z'
怎么办?然后,代码中的这一行Saint Jose,23.0
将替换为stripped = line.replace(' ','')
。
无论如何,要解决这个问题,它很简单,并且可以通过一些正则表达式完成。
SaintJose,23.0
使用生成器表达式可以缩短它:
import re #python regex
def read_file(fileName):
pattern = re.compile(r'(.*?),([-+]?(?:\d+\.\d*|\.?\d+)(?:[eE][-+]?\d+)?)')
with open(fileName) as weatherFile:
for line in weatherFile:
if not pattern.fullmatch(line.strip()):
continue
town, rain = line.split(",")
if checkIfExists(town):
dataList.append({"city":town, "average_rainfall":float(rain.rstrip())})
else:
print("It looks like {0} is on the list twice. Please ensure all towns in {1} only appear once and try again." .format(town, fileName))
break
这一行:
def read_file(fileName):
pattern = re.compile(r'(.*?),([-+]?(?:\d+\.\d*|\.?\d+)(?:[eE][-+]?\d+)?)')
with open(fileName) as weatherFile:
for town, rain in (line.split(",") for line in weatherFile if pattern.fullmatch(line.strip()))
if checkIfExists(town):
dataList.append({"city":town, "average_rainfall":float(rain.rstrip())})
else:
print("It looks like {0} is on the list twice. Please ensure all towns in {1} only appear once and try again." .format(town, fileName))
break
编译正则表达式以供重用。对于复杂的正则表达式,这通常更有效,因此每次使用正则表达式进行匹配时,正则表达式引擎都不必重新评估和重建它的内部状态。
没有预编译正则表达式的匹配等价物将是:
pattern = re.compile(r'(.*?),([-+]?(?:\d+\.\d*|\.?\d+)(?:[eE][-+]?\d+)?)')
你看到的可怕的正则表达式(这一个re.fullmatch(your_string_expression, r'(.*?),([-+]?(?:\d+\.\d*|\.?\d+)(?:[eE][-+]?\d+)?)')
)用于匹配整数或浮点数,这就是为什么它太长了。 Python有一些定义的here。我在这里使用的那个结合了匹配的整数和浮点数,你可以看到它的一个使用here的例子。
答案 1 :(得分:0)
有些人在面对问题时会想“我知道,我会使用正则表达式”。现在他们有两个问题。 (Jamie Zawinski)
将(.*?),([-+]?(?:\d+\.\d*|\.?\d+)(?:[eE][-+]?\d+)?)
正则表达式与下面提出的以下验证定义进行比较:
validators = {
'City Name': [
UniqueValidator()
],
'Average Rainfall': [
FloatValidator()
]
}
Regular Expressions: Now You Have Two Problems
我会将该文件视为CSV文件,这样我们就可以使用csv
module来阅读它,并使用像vladiate
这样的CSV架构验证包。您不必为此问题使用第三方,但它提供了一个很好的关注点分离,并允许一个很好的验证逻辑定义。
例如,如果您的cities.csv
文件包含以下内容(请注意“平均降雨量”列中的invalid_value
):
City Name,Average Rainfall
towna,2.43
townb,1.01
townc,invalid_value
并且,执行以下代码(注意我们如何定义唯一的“城市名称”值要求和“平均降雨量”的浮动值验证器):
import csv
from vladiate import Vlad
from vladiate.validators import UniqueValidator, FloatValidator
from vladiate.inputs import LocalFile
class CityValidator(Vlad):
validators = {
'City Name': [
UniqueValidator()
],
'Average Rainfall': [
FloatValidator()
]
}
def read_file(file_name):
CityValidator(source=LocalFile(file_name)).validate()
with open(file_name) as weather_file:
reader = csv.reader(weather_file)
for city_name, average_rainfall in reader:
print(city_name, average_rainfall)
read_file("cities.csv")
你会看到打印:
City Name Average Rainfall
towna 2.43
townb 1.01
townc invalid_value
Validating CityValidator(source=LocalFile('cities.csv'))
Failed :(
FloatValidator failed 1 time(s) (33.3%) on field: 'Average Rainfall'
Invalid fields: ['invalid_value']