Linux中用Bash正则表达式筛选CSV:保留2010-2011年排除'all countries'
分号分隔CSV筛选方案:保留2010-2011年数据并排除指定Country值
问题背景
处理分号分隔的CSV文件,表头如下:
Unnamed: 0;Unnamed: 0.1;year;country;word;frequency;count;freq_prop_headlines;word_len;freq_rank;hfreq_rank;theme
需求:筛选year列值为2010或2011的行,同时排除country列值为"all countries"的行。
错误分析
你之前尝试的正则^([^;]*;){2}(2010|2011);^all countries.*;无效,原因是:
- 错误重复使用行首锚点
^,年份后的^强制匹配行开头,逻辑矛盾 - 没有正确表达"country列不等于all countries"的匹配规则
可行解决方案
方案一:组合正向+反向匹配(兼容性好)
用两次grep分别实现筛选年份和排除指定country值,逻辑清晰:
# 先筛选2010/2011年的行,再排除country为all countries的行 grep -E '^([^;]*;){2}(2010|2011);' "$1" | grep -v '^[^;]*;[^;]*;[^;]*;all countries;'
- 第一个
grep:匹配前两个分号后是2010或2011的行(对应year列) - 第二个
grep -v:反向匹配前三个分号后是"all countries;"的行(对应country列),排除这类行
方案二:单一正则表达式(需GNU grep支持)
使用Perl风格正则的负向预查,一次完成匹配:
grep -P '^([^;]*;){2}(2010|2011);(?!all countries;)' "$1"
(?!all countries;)是负向预查,确保year列之后的内容不是"all countries;",即country列不等于该值
保留表头的扩展方案
如果需要保留CSV表头,可先输出表头再处理数据行:
head -n 1 "$1" && grep -E '^([^;]*;){2}(2010|2011);' "$1" | grep -v '^[^;]*;[^;]*;[^;]*;all countries;'
内容的提问来源于stack exchange,提问作者Uri
相关产品推荐
相关产品推荐

