У меня есть два файла, один из них содержит список строк.
+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
не находится под контролем.
решение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 неопределенным, так что один вызов <>
there, поглощает весь первый файл ( 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 вместо того, чтобы передавать его в качестве аргумента. <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) }
- если значение 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"