Python - 从文本文件确认字符串匹配格式

时间:2017-12-11 03:12:33

标签: python python-3.x validation

我有一个程序需要将文本文件作为输入,并对每行代码执行一些操作。

在我可以对文本文件做任何事情之前,我需要确保每一行都匹配一个特定的格式,在这种情况下,它将是城市名称(可以是任何字符串,它不需要是真实的城市名称)后跟一个','后跟一个数字。

典型的线条如下所示:

  

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

2 个答案:

答案 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']