根据给定格式验证CSV

时间:2009-09-07 05:17:31

标签: python regex csv

我希望用户将最大1MB的CSV文件上传到符合以下格式的给定格式的网络表单:

"<String>","<String>",<Int>,<Float>

稍后会处理。我想验证文件是否符合指定的格式,以便稍后使用该文件的程序不会收到意外的输入,并且没有安全问题(比如针对进行某些计算和db插入的解析脚本的一些注入攻击)。

(1)这样做的最佳方式是快速彻底的?根据我的研究,我可以走正则表达式的路径或更像this的东西。我查看了python csv模块,但似乎没有任何内置验证。

(2)假设我选择正则表达式,有人能指导我做最好的方法吗?我是否匹配非法字符并拒绝该字符? (例如,没有'/''\''&lt;''&gt;''{''}'等)或匹配所有合法的例如。 [a-zA-Z0-9] {1,10}为字符串组件?我不太熟悉正则表达式,所以指点或示例将不胜感激。

编辑: 字符串不应包含逗号或引号,只包含名称(即名字,姓氏)。是的,我忘了添加它们会被双引号。

编辑#2:编辑#2: 感谢所有的答案。 Cutplace非常有趣,但它是独立的。最终决定采用pyparsing,因为如果我添加更多格式,它会提供更大的灵活性。

6 个答案:

答案 0 :(得分:4)

Pyparsing将处理这些数据,并且可以容忍诸如逗号之前和之后的空格,引号内的逗号等意外事件。(csv模块也是如此,但正则表达式解决方案迫使你添加“\ s *”位全部这个地方)。

from pyparsing import *

integer = Regex(r"-?\d+").setName("integer")
integer.setParseAction(lambda tokens: int(tokens[0]))
floatnum = Regex(r"-?\d+\.\d*").setName("float")
floatnum.setParseAction(lambda tokens: float(tokens[0]))
dblQuotedString.setParseAction(removeQuotes)
COMMA = Suppress(',')
validLine = dblQuotedString + COMMA + dblQuotedString + COMMA + \
        integer + COMMA + floatnum + LineEnd()

tests = """\
"good data","good2",100,3.14
"good data" , "good2", 100, 3.14
bad, "good","good2",100,3.14
"bad","good2",100,3
"bad","good2",100.5,3
""".splitlines()

for t in tests:
    print t
    try:
        print validLine.parseString(t).asList()
    except ParseException, pe:
        print pe.markInputline('?')
        print pe.msg
    print

打印

"good data","good2",100,3.14
['good data', 'good2', 100, 3.1400000000000001]

"good data" , "good2", 100, 3.14
['good data', 'good2', 100, 3.1400000000000001]

bad, "good","good2",100,3.14
?bad, "good","good2",100,3.14
Expected string enclosed in double quotes

"bad","good2",100,3
"bad","good2",100,?3
Expected float

"bad","good2",100.5,3
"bad","good2",100?.5,3
Expected ","

您可能会在将来某个时间删除这些引号,pyparsing可以通过添加以下内容在分析时执行此操作:

dblQuotedString.setParseAction(removeQuotes)

如果您想为输入文件添加评论支持,请说出“#”后跟剩下的行,您可以这样做:

comment = '#' + restOfline
validLine.ignore(comment)

您还可以为这些字段添加名称,以便您可以按名称而不是索引位置访问它们(我发现根据路上的变化,我会找到更强大的代码):

validLine = dblQuotedString("key") + COMMA + dblQuotedString("title") + COMMA + \
        integer("qty") + COMMA + floatnum("price") + LineEnd()

然后您的后处理代码就可以执行此操作:

data = validLine.parseString(t)
print "%(key)s: %(title)s, %(qty)d in stock at $%(price).2f" % data
print data.qty*data.price

答案 1 :(得分:2)

我投票赞成解析文件,检查你每个记录有4个组件,前两个组件是字符串,第三个是int(检查NaN条件),第四个是浮点数(也是检查NaN条件)。

Python将是一个很好的工具。

我不知道Python中有任何库可以根据规范处理CSV文件的验证,但实际上写起来并不是很难。

import csv
import math

dataChecker = csv.reader(open('data.csv'))
for row in dataChecker:
    if len(row) != 4:
        print 'Invalid row length.'
        return

    my_int = int(row[2])
    my_float = float(row[3])

    if math.isnan(my_int):
        print 'Bad int found'
        return

    if math.isnan(my_float):
        print 'Bad float found'
        return

print 'All good!'

答案 2 :(得分:1)

这是我制作的一个小片段:

import csv 

f = csv.reader(open("test.csv"))

for value in f:
    value[0] = str(value[0])
    value[1] = str(value[1])
    value[2] = int(value[2])
    value[3] = float(value[3])

如果使用不具有指定格式的文件运行该文件,则会出现异常:

$ python valid.py 
Traceback (most recent call last):
  File "valid.py", line 8, in <module>
    i[2] = int(i[2])
ValueError: invalid literal for int() with base 10: 'a3'

然后你可以尝试使用一个尝试 - 除了ValueError来捕获它并让用户知道他们做错了什么。

答案 3 :(得分:1)

解析CSV可能会有很多例子,所以你可能不想尝试“手工”。至少从内置于您正在使用的语言的软件包/库开始,即使它没有完成您能想到的所有“验证”。

到达那里后,检查“非法”字符列表的字段,或检查每个字段中的值以确定它们是否有效(如果可以的话)。你甚至不需要一个正则表达式来完成这个任务,但这样做可能更简洁。

您可能还禁止使用嵌入式\ r \ n或\ n,\ 0或\ t。只需遍历字段并在使用csv lib加载数据后检查它们。

答案 4 :(得分:1)

试试Cutplace。它验证表格数据是否符合界面控制文档

答案 5 :(得分:0)

理想情况下,您希望过滤尽可能具有限制性 - 您允许的内容越少,潜在的攻击途径就越少。例如,float或int字段具有非常少量的字符(并且这些字符的配置非常少),实际上应该允许这些字符。理想情况下,字符串过滤应仅限于人们有理由输入的字符 - 如果不知道较大的上下文,则很难准确地告诉您应该允许哪些字符,但至少字符串匹配正则表达式应该需要引用字符串并且不允许任何可以提前终止字符串的东西。

但请记住,某些名称可能包含单引号(例如“O'Neil”)或短划线等内容,因此您无法将这些内容排除在外。

像...一样的东西。

/"[a-zA-Z' -]+"/

...对于应该包含名称的双引号字符串可能是理想的。如果您想强制执行某些长度,则可以将+替换为{x,y}长度最小值/最大值。