1 个不稳定版本
使用旧的 Rust 2015
0.1.0 | 2019 年 2 月 6 日 |
---|
#1085 在 文本处理
49KB
988 行
csv-sanity
在一个充满格式错误、验证不良的 CSV 文件的世界中保持你的理智。快速高效地清理和转换包含数百万记录的大型 CSV 文件。
注意: csv-sanity 处于 alpha 状态,可能会发生破坏性更改。特别是规则集文件语法可能在不久的将来发生变化。我亲自在多个项目中使用了 csv-sanity,它非常有帮助,但与大多数 alpha 软件一样,csv-sanity 是按原样提供的,不提供任何保证或保修。请自行承担风险,并仔细检查转换后的文件!
目的
CSV 格式没有很好地标准化,在存储具有复杂数据格式的大量记录时存在许多不足,但 CSV 作为大多数 CRM 和数据库软件可以解析和理解的通用交换格式在许多领域无处不在。
但是,当你的 CRM 只能解析 ISO 8601 格式的日期,而你继承的 CSV 中的日期格式如下时会发生什么
id,name,signup_date
2,John Doe,11/22/2017
3,Jane Doe,11/28/2017
或者你收到了一个需要通过个性化电子邮件联系的人的 CSV 文件,但 CSV 中的联系人姓名全部大写
id,first_name,last_name
2,JOHN,DOE
3,JANE,DOE
或者你有一个 CSV 文件,其中大多数记录具有有效值,但每 20k 个记录中有 1 个无意义的值导致整个导入中断
id,fist_name,last_name,party_registration
2,Jane,Doe,REP
3,John,Doe,DEM
345,Josh,Smith,HAHAHAHA
或者甚至有一个由于未转义逗号而格式不正确的 CSV 文件
id,first_name,last_name,email
2,Jane,Doe,jane@example.com
3,John,Doe,"i,don't,follow,the,rules"@example.com
这些都是我多年来遇到的真实问题。如果 CSV 足够小,可以通过手动修改来纠正,但对于具有 10k、100k 或甚至数百万记录的 CSV,手动修改根本不是可行的选择。
csv-sanity
旨在解决清理大型、验证不良的 CSV 文件的问题。
用法
csv-sanity
是一个可执行文件,它接受要处理的输入 CSV 文件和一个定义要应用转换规则的 JSON 规则集文件
csv-sanity [-r RULESET_FILE] <INPUT_FILE>
如果没有通过 -r
选项提供规则集文件的路径,csv-sanity
将在当前目录中查找名为 "ruleset.json" 的文件。
默认情况下,csv-sanity
将在当前目录中输出两个文件:output.csv,包含经过验证和转换的记录的处理后的CSV文件,以及errors.csv,包含无法处理的记录和字段列表以及它们被拒绝的原因。输出和错误文件的路径可以通过-o FILE_PATH
和-e FILE_PATH
选项分别覆盖。
ruleset.json 语法
规则集文件是JSON文件,用于定义一组转换规则以及它们应该应用到的字段。
以下是一个示例规则集JSON文件
{
"rules": [
{
"applicability": {
"Global": [],
},
"transformer": {
"None": {
"regex": "\\A(?:[:cntrl:]|\\s)*\\z"
}
},
"priority": -10
},
{
"applicability": {
"Global": [],
},
"transformer": {
"Trim": {}
},
"priority": -10
},
{
"applicability": {
"Fields": {
"field_names": [
"first_name",
"last_name"
]
}
},
"transformer": {
"Capitalize": {}
}
}
]
}
每个ruleset.json文件都是一个包含单个"rules"字段的JSON对象,该字段包含一个规则对象数组。
规则是具有两个字段的对象
- "applicability":指定规则是全局应用还是仅应用于预定义的一组字段(指定为正在处理的CSV中的列标题)
- "transformer":转换器对象,用于指定应如何转换适用的字段。
转换器
大写
{
"Capitalize": {}
}
将字符串字段转换为大写。
选择
{
"Choice": {
"choices": [
"A",
"B",
"C"
]
}
}
仅接受预定义的接受值列表,并拒绝其余的值。
日期
{
"Date": {
"input_formats": [
"%m/%d/%Y"
],
"output_formats": "%F"
}
}
尝试通过time::strptime使用一系列日期时间格式解析字段。有关日期时间格式语法的详细信息,请参阅time crate的文档。
电子邮件
{
"Email": {}
}
尝试将字段解析为电子邮件地址,拒绝任何看起来无效的电子邮件地址的字段。
无
{
"None": {
"regex": "\\A(?:[:cntrl:]|\\s)*\\z"
}
}
将匹配的字段替换为空白值。在CSV文件中用作全局规则以规范化空白字段很有用。
数字
{
"Number": {}
}
尝试将字段解析为整数,拒绝无法解析的字段。
电话号码
{
"PhoneNumber": {}
}
尝试将文件解析为美国、NANP格式的电话号码,并将它们转换为标准国际格式+1 <area_code> <exchange_code> <subscriber_number>
。
正则表达式
{
"Regex": {
"regex": "\\A([A-Z])[A-Z]+\\z",
"template": "$1"
}
}
将字段与提供的正则表达式模式进行匹配,并根据模板字符串进行转换,替换捕获组占位符。有关正则表达式crate文档中的Regex::replace
的详细信息。
正则表达式匹配
{
"RegexMatch": {
"regex": "\\A[A-Z]{2,3}\\z",
"negate": false
}
}
拒绝任何无法与提供的正则表达式模式匹配的字段。如果negate
为true
,则拒绝任何与提供的正则表达式模式匹配的字段。
修剪
{
"Trim": {}
}
从字段中删除前导和尾随空格。用作全局规则以规范字段和删除无用空格很有用。
邮政编码
{
"Zipcode": {}
}
尝试将字段解析为美国邮政编码,格式为"xxxxx"和"xxxxx-xxxx",拒绝任何无法匹配该格式的字段。
依赖关系
~8MB
~148K SLoC