Изменить список строк на строчные буквы

Изменить список строк на строчные буквы

У меня есть два файла, один из них содержит список строк.

+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"

Связанный контент