sed脚本替换CSV第五字段内小于100数字为字符串的问题
问题:用sed替换CSV第五字段中小于100的数字为"none"
需通过sed脚本将逗号分隔的CSV文件第五字段中小于100的数字替换为"none",现有脚本错误替换了大数字的开头部分,且要求不能使用awk。
示例CSV
datetime,car,brand,model,km,new 10/10/1949 20:30,yes,ford,f150,20,yes 10/10/1949 20:30,no,yamaha,r7,1560,yes 10/10/1949 20:30,yes,renault,twingo,37,yes 10/10/1949 20:30,no,honda,cbr600rr,2000,no
现有错误脚本
# Replace s/\([^,]*,[^,]*,[^,]*,[^,]*\,\)\(0\|[1-9][0-9]\{0,1\}\)\([^,]*\)/\1none\3/
执行命令
sed -f script.sed ./sample.csv
期望输出
datetime,car,brand,model,km,new 10/10/1949 20:30,yes,ford,f150,none,yes 10/10/1949 20:30,no,yamaha,r7,1560,yes 10/10/1949 20:30,yes,renault,twingo,none,yes 10/10/1949 20:30,no,honda,cbr600rr,2000,no
实际错误输出
datetime,car,brand,model,km,new 10/10/1949 20:30,yes,ford,f150,none,yes 10/10/1949 20:30,no,yamaha,r7,none60,yes 10/10/1949 20:30,yes,renault,twingo,none,yes 10/10/1949 20:30,no,honda,cbr600rr,none00,no
问题原因
原脚本的正则仅匹配了第五字段中数字的开头1-2位(比如1560中的15),后续的[^,]*会保留剩余字符,导致替换后出现none60这类错误结果。核心是没有限定匹配的数字必须是整个第五字段的内容,即数字后必须紧跟逗号或行尾。
修正后的脚本
# Replace fifth field (km) with "none" if value is <100 s/\([^,]*,[^,]*,[^,]*,[^,]*,\)\([0-9]\{1,2\}\)\(,\|$\)/\1none\3/
正则解释
\([^,]*,[^,]*,[^,]*,[^,]*,\):精准匹配前四个字段及末尾的逗号,捕获为分组1\([0-9]\{1,2\}\):匹配1-2位数字(0-99),捕获为分组2\(,\|$\):匹配第五字段后的逗号或行尾,确保匹配的是整个字段的数字,捕获为分组3- 替换逻辑:将分组2的内容替换为
none,保留分组1和分组3的原始内容
如果需要排除以0开头的两位数(比如05这类无效数字,仅保留0和1-99的有效数字),可调整正则为:
s/\([^,]*,[^,]*,[^,]*,[^,]*,\)\(0\|[1-9][0-9]\?\)\(,\|$\)/\1none\3/
验证结果
执行原命令后,输出与期望输出完全一致。
内容的提问来源于stack exchange,提问作者Christian Cid
相关产品推荐
相关产品推荐

