Tengo dos archivos, un archivo contiene una lista de cadenas.
+stringa +Dog +Cat
+cat +Tux +elephant
y el segundo archivo (csv) contiene algo como:
"123456 Abc","+Stringx +123","something"
"23456 dEf","+cat +Tux +elephant","Other something"
"34524 xyz","+stringa +Dog +Cat","third something"
el resultado debería ser:
"123456 Abc","+Stringx +123","something"
"23456 dEf","+cat +tux +elephant","Other something"
"34524 xyz","+stringa +dog +cat","third something"
¿Cómo puedo cambiar las cadenas que coinciden con mi lista de patrones a minúsculas?
Mi archivo de valores separados por comas tiene aproximadamente 30 columnas y aproximadamente 1500 filas.
Respuesta1
Con GNU sed
, se supone que no tiene ningún metacarácter en la lista de cadenas, +
no es un metacarácter con BRE predeterminado
$ # 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
para convertir cadena a minúsculasg
para reemplazar todas las apariciones en una línea,i
para coincidencias que no distinguen entre mayúsculas y minúsculas
Si no tienesGNU 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"
Como señaló Stéphane Chazelas, esto podría provocar vulnerabilidades de inyección de código si el contenido f1
no está bajo control.
Respuesta2
Conperl
, suponiendo que quieras cada unopalabraen el primer archivo que se pondrá en minúsculas:
perl -pe '
BEGIN {local $/ = undef; $regex = join "|", map qr{\Q$_\E}i, split " ", <>}
s/$regex/\L$&/g' file1.words file2.csv
local $/ = undef
hace que el separador de registros para el bloque BEGIN sea indefinido, de modo que la única invocación de <>
allí absorba todo el primer archivo ( file1.words
). Lo dividimos en espacios en blanco ( split " "
es especial en perl
de la misma manera que awk -F " "
en awk
) y unimos las palabras resultantes con|
después de habercitado con expresiones regularesy los hizo sin distinción entre mayúsculas y minúsculas.
Entonces tenemos una expresión regular enorme que es algo así como (?i:word1)|(?i:word2)|...
la que aplicamos en cada línea del segundo archivo en el resto del código.
Si es cada cadena en cadalíneadel primer archivo, entonces eso se puede simplificar a:
perl -pe '
BEGIN {chomp (@strings = <STDIN>); $regex = join "|", map qr{\Q$_\E}i, @strings}
s/$regex/\L$&/g' < file1.strings file2.csv
Allí, abrimos el primer archivo en stdin en lugar de pasarlo como argumento. <STDIN>
devuelve una lista de sus líneas de las cuales eliminamos los delimitadores con chomp
y unimos con |
como se indicó anteriormente.
Si no desea que se limite a caracteres ASCII, agregue la -Mopen=locale
opción.
Respuesta3
AWK
solución (para su entrada actual):
Suponiendo que el segundo campo es de interés principal y los valores en el archivo de búsqueda están entre comillas dobles.
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"
- envolver unpatrónlínea con comillas dobles mientras se itera a través de las líneas delpatterns
archivoa[$0]
- capturar unpatrónlínea en matriza
$2 in a{ $2=tolower($2) }
- si el valor del segundo campo de la línea delfile.csv
archivo está en la lista de patrones (es decir, matriza
), convierta todos los caracteres que contiene a minúsculas$2=tolower($2)
La salida:
"123456 Abc","+Stringx +123","something"
"23456 dEf","+cat +tux +elephant","Other something"
"34524 xyz","+stringa +dog +cat","third something"