我有两个文件,一个文件包含字符串列表。
+stringa +Dog +Cat
+cat +Tux +elephant
第二个文件 (csv) 包含类似以下内容的内容:
"123456 Abc","+Stringx +123","something"
"23456 dEf","+cat +Tux +elephant","Other something"
"34524 xyz","+stringa +Dog +Cat","third something"
结果应该是:
"123456 Abc","+Stringx +123","something"
"23456 dEf","+cat +tux +elephant","Other something"
"34524 xyz","+stringa +dog +cat","third something"
如何将与我的模式列表匹配的字符串更改为小写?
我的逗号分隔值文件大约有 30 列和大约 1500 行。
答案1
使用GNU sed
, 假设字符串列表中没有任何元字符,+
不是默认 BRE 的元字符
$ # create substitute command for each line
$ sed 's/.*/s|"&"|\\L\&|gi/' f1
s|"+stringa +Dog +Cat"|\L&|gi
s|"+cat +Tux +elephant"|\L&|gi
$ # pass those commands as sed script
$ sed -f <(sed 's/.*/s|"&"|\\L\&|gi/' f1) ip.csv
"123456 Abc","+Stringx +123","something"
"23456 dEf","+cat +tux +elephant","Other something"
"34524 xyz","+stringa +dog +cat","third something"
$ # or save them in a file and use
$ sed 's/.*/s|"&"|\\L\&|gi/' f1 > f2
$ sed -f f2 ip.csv
\L
将字符串转换为小写g
用于替换行中所有出现的情况,i
用于不区分大小写的匹配
如果你没有GNU sed
$ # \Q to quote metacharacters
$ # but will have issues if you have \ or $ or @
$ sed 's/.*/s|\\Q"&"|\\L$\&|gi;/' f1
s|\Q"+stringa +Dog +Cat"|\L$&|gi;
s|\Q"+cat +Tux +elephant"|\L$&|gi;
$ perl -p <(sed 's/.*/s|\\Q"&"|\\L$\&|gi;/' f1) ip.csv
"123456 Abc","+Stringx +123","something"
"23456 dEf","+cat +tux +elephant","Other something"
"34524 xyz","+stringa +dog +cat","third something"
f1
正如 Stéphane Chazelas 所指出的,如果内容不受控制, 这可能会导致代码注入漏洞
答案2
与perl
,假设您想要每个单词在第一个要转换为小写的文件中:
perl -pe '
BEGIN {local $/ = undef; $regex = join "|", map qr{\Q$_\E}i, split " ", <>}
s/$regex/\L$&/g' file1.words file2.csv
local $/ = undef
使 BEGIN 块的记录分隔符未定义,以便对那里的一次调用<>
,将整个第一个文件 ( file1.words
) 吞入其中。我们将其拆分为空白(与中的方式相同split " "
),并将结果单词与在拥有以后perl
awk -F " "
awk
|
正则表达式引用它们并使它们不区分大小写。
因此,我们有一个巨大的正则表达式,类似于(?i:word1)|(?i:word2)|...
我们在代码的其余部分中应用到第二个文件的每一行的东西。
如果是每个字符串中的每个线第一个文件的,那么可以简化为:
perl -pe '
BEGIN {chomp (@strings = <STDIN>); $regex = join "|", map qr{\Q$_\E}i, @strings}
s/$regex/\L$&/g' < file1.strings file2.csv
在那里,我们在标准输入上打开第一个文件,而不是将其作为参数传递。<STDIN>
返回其行的列表,我们从中删除分隔符chomp
, 并按上面的方式连接|
。
如果您不希望限制为 ASCII 字符,请添加该-Mopen=locale
选项。
答案3
AWK
解决方案(针对您当前的输入):
假设第二个字段是主要关注点,并且搜索文件中的值用双引号引起来。
awk 'NR==FNR{ $0="\042"$0"\042"; a[$0]; next }
$2 in a{ $2=tolower($2) }1' patterns FS=',' OFS=',' file.csv
$0="\042"$0"\042"
- 包裹一个图案patterns
迭代文件行时使用双引号的行a[$0]
- 捕获一个图案行入数组a
$2 in a{ $2=tolower($2) }
- 如果文件行的第二个字段值file.csv
位于模式列表中(即数组a
) - 将其中的所有字符转换为小写$2=tolower($2)
输出:
"123456 Abc","+Stringx +123","something"
"23456 dEf","+cat +tux +elephant","Other something"
"34524 xyz","+stringa +dog +cat","third something"