我有一个CSV文件,其中包含一个我希望筛选的列。我想使用模式文件来查找模式存在的所有条目,即使在列的值的一部分中,并使用此“模式”替换整个单元格值。 我列出了一些我想用作“模式”银行的关键词; 因此,如果此列中的单元格(此情况仅为第二个)将此“模式”作为其字符串的一部分,那么我想用此“模式”替换整个单元格。
所以例如:
我的目标文件:
id1,Taxidermy Equipment & Supplies,moreinfo1
id2,Taxis & Private Hire,moreinfo2
id3,Tax Services,moreinfo3
id4,Tools & Hardware,moreinfo4
id5,Tool Sharpening,moreinfo5
id6,Tool Shops,moreinfo6
id7,Video Conferencing,moreinfo7
id8,Video & DVD Shops,moreinfo8
id9,Woodworking Equipment & Supplies,moreinfo9
我的“模式”文件:
Taxidermy Equipment & Supplies
Taxis
Tax Services
Tool
Video
Wood
输出文件:
id1,Taxidermy Equipment & Supplies,moreinfo1
id2,Taxis,moreinfo2
id3,Tax Services,moreinfo3
id4,Tool,moreinfo4
id5,Tool,moreinfo5
id6,Tool,moreinfo6
id7,Video,moreinfo7
id8,Video,moreinfo8
id9,Wood,moreinfo9
我想出了通常的“查找和替换”sed:
sed -i 's/PATTERN/REPLACE/g' file.csv
但我想让它在特定的列上运行,所以我提出了:
awk 'BEGIN{OFS=FS="|"}$2==PATTERN{$2=REPLACE}{print}' file.csv
但它不适用于“字符串的一部分”([视频]:“视频和DVD商店” - >“视频”),我似乎无法得到它如何将awk作为文件输入对于“模式”块。
这是否有awk脚本?或者我必须写一些东西(例如在python中使用内置的csv套装?)
答案 0 :(得分:2)
在awk中,使用index
。它只会在更换时打印记录,但即使没有匹配也很容易修改打印(例如将print $1,i,$3}
替换为$0=$1 OFS i OFS $3} 1
):
$ awk -F, -v OFS=, '
NR==FNR { a[$1]; next } # store "patterns" to a arr
{ for(i in a) # go thru whole a for each record
if(index($2,i)) # if "pattern" matches $2
print $1,i,$3 # print with replacement
}
' pattern_file target_file
id1,Taxidermy Equipment & Supplies,moreinfo1
id2,Taxis,moreinfo2
id3,Tax Services,moreinfo3
id4,Tool,moreinfo4
id5,Tool,moreinfo5
id6,Tool,moreinfo6
id7,Video,moreinfo7
id8,Video,moreinfo8
id9,Wood,moreinfo9
答案 1 :(得分:1)
Perl解决方案,使用Text::CSV_XS:
#!/usr/bin/perl
use warnings;
use strict;
use Text::CSV_XS qw{ csv };
my ($input_file, $pattern_file) = @ARGV;
open my $pfh, '<', $pattern_file or die $!;
chomp( my @patterns = <$pfh> );
my $aoa = csv(in => $input_file);
for my $line (@$aoa) {
for my $pattern (@patterns) {
if (-1 != index $line->[1], $pattern) {
$line->[1] = $pattern;
last
}
}
}
csv(in => $aoa, quote_space => 0, eol => "\n", out => \*STDOUT);
答案 2 :(得分:1)
这是(主要)awk解决方案:
#/bin/bash
patterns_regex=`cat patterns_file | tr '\n' '|'`
cat target_file | awk -F"," -v patterns="$patterns_regex" '
BEGIN {
OFS=",";
split(patterns, patterns_split, "|");
}
{
for (pattern_num in patterns_split) {
pattern=patterns_split[pattern_num];
if (pattern != "" && $2 ~ pattern) {
print $1,pattern,$3
}
}
}'
答案 3 :(得分:1)
如果要使用sed
解决此问题,则需要执行一些步骤
对于每个模式,您将需要一个像
sed 's/^\([^,]*\),\(.*Tool.*\),/\1,Tool,/' inputfile
您需要两次每个模式,您可以使用
翻译模式文件sed 's/.*/"&" "&"/' patternfile
# Change the / into #, thats easier for the final command
sed 's#.*#"&" "&"#' patternfile
当您指示sed读取命令文件时,您需要使用sed
开始每一行。命令文件看起来像
sed 's#.*#s/^\\([^,]*\\),\\(.*&.*\\),/\\1,&,/#;s#&#\\&#g' patternfile
您可以存储这是一个文件并使用该文件,但通过进程替换,您可以执行
之类的操作cat <(echo "Now this line from echo is handled as a file")
尼斯。让我们测试解决方案
sed -f <(sed 's#.*#s/^\\([^,]*\\),\\(.*&.*\\),/\\1,&,/#' patternfile) inputfile
几乎就在那里!只有第一个输出线很奇怪。发生了什么事?
第一个模式有&
,具有特殊含义
我们可以通过在模式中添加反斜杠来修补命令:
sed -f <(sed 's#.*#s/^\\([^,]*\\),\\(.*&.*\\),/\\1,&,/#;s#&#\\&#g' patternfile) inputfile