Solo tuve acceso a busybox 1.27.2
.
Actualmente estoy procesando un diccionario con más de medio millón de palabras y más de 6.000 páginas (que fue extraído de un PDF con ghostscript y convertido a texto plano). Está en un 20MB
.txt
archivo. Originalmente, cada palabra de este diccionario tiene un inicio ->
para facilitar la búsqueda de una palabra.
Lo que intento lograr es que sea *nix
amigable. Lo que significa que si hago esto:
grep -e '->myfancyword' ./dictionary.txt
.
Debería obtener como resultado:
->fancyword: This is a very fancy word. *Definition going on for more than 6 lines*
Esto se hace fácilmente eliminando todas las nuevas líneas \n
para que cada palabra tenga toda su definición en una línea muy larga, lo cual está bien. Puedo reemplazar todo \n
con tr -d '\n'
y luego tener el resultado de eso, sed 's/->/\n->/g'
por lo que terminaré con la definición de todas las palabras en una sola línea. Incluso en este documento enorme, es algo que se hace en menos de 5 segundos.
Casi estoy obteniendo el resultado que quiero, pero no es perfecto. Puedo hacer esto grep -e '->word' ./dictionary.txt
y obtener la definición completa de la palabra. Pero no es cosméticamente perfecto.
La razón por la que no estoy satisfecho con el resultado es porque el pdf original fue formateado para imprimirse en A4
páginas, lo que significa que cuando hay una palabra larga, se corta. Como esto:
p.ej
->word: This is a defini-
tion.
Si proceso el archivo con el flujo de trabajo anterior, obtengo: ->word: This is a defini- tion.
al buscar la palabra deseada.
Hasta ahora lo que logré lograr es esto:
- aporte
->firstword: This is a defini-
tion.
->secondword: This is a second defini-
tion.
aplicado
tr -d '\n' < ./dictionary.txt > ./dictionary2.txt
la salida es:
->firstword: This is a defini- tion. ->secondword: This is a second defini- tion.
corrió:
sed -e 's/->/\n->/g' ./dictionary2.txt
Terminando con:
producción
->firstword: This is a defini- tion.
->secondword: This is a second defini- tion.
Antes incluso de realizar el segundo paso, me gustaría eliminar el guión y la nueva línea ( -\n
) para "unir" todas las líneas cortadas.
Entonces, mi pregunta es: ¿Cómo puedo sustituir/eliminar la cadena específica que contiene el guión -
y el carácter de nueva línea \n
( -\n
) al final de la línea?
Lo que me gusta conseguir es:
salida (por favor, verifique que el guión y el espacio ( -
) ya no estén presentes)
->firstword: This is a definition.
->secondword: This is a second definition.
Gracias.
EDITAR:
Esta es una página del archivo PDF:
->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
->abigeo. (Del lat. abigeus). 1. m. Am. Ladrón de ganado.
->abigotado, da. 1. adj. bigotudo.
->abinar. 1. tr. rur. y vulg. Binar la tierra.
->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia y
adjudicación de bienes de quien muere sin testar.
->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-
tiendo de materia inerte. 2. f. Bioquím. síntesis abiótica.
->abiótico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. síntesis
abiótica
->abipón, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca del
Paraná. U. t. c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familia
guaicurú hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, o en otros objetos.
->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice de
las zonas del mar profundo que se extienden más allá del talud continental, y corresponden a
profundidades mayores de 2000 m. 3. adj. Perteneciente o relativo a tales zonas.
->abiselar. 1. tr. biselar.
->abisinio, nia. 1. adj. Natural de Abisinia, hoy Etiopía. U. t. c. s. 2. adj. Perteneciente o re-
lativo a este país de África. 3. m. Lengua abisinia. V. rito abisinio
->abismado, da. (Del part. de abismar). 1. adj. Dicho de una persona, de su expresión, de
su gesto, etc.: Ensimismados, reconcentrados. 2. adj. Heráld. Dicho de una pieza del escudo:
Puesta en el abismo.
->abismal (1). (Del ár. hisp. almismár, y este del ár. clás. mismar). 1. m. Cada uno de los
clavos con que se fijaba en el asta el hierro de la lanza.abismal2. 1. adj. Perteneciente o re-
lativo al abismo. 2. adj. Muy profundo, insondable, incomprensible.
->abismar. 1. tr. Hundir en un abismo. U. t. c. prnl. 2. tr. Confundir, abatir. U. t. c. prnl. 3.
prnl. Entregarse del todo a la contemplación, al dolor, etc. 4. prnl. Am. sorprenderse (|| con-
moverse con algo imprevisto o raro).
->abismático, ca. 1. adj. abismal2.
->abismo. (Quizá del lat. vulg. *abyssimus, der. de abyssus, y este del gr. , sin fondo). 1.
m. Profundidad grande, imponente y peligrosa, como la de los mares, la de un tajo, la de una
sima, etc. U. t. en sent. fig. Se sumió en el abismo de la desesperación. 2. m. infierno (|| lugar
de castigo eterno). 3. m. Cosa inmensa, insondable o incomprensible. 4. m. Diferencia
grande entre cosas, personas, ideas, sentimientos, etc. 5. m. Heráld. Punto o parte central
del escudo. 6. m. Nic. Maldad, perdición, ruina moral.
Esto es lo que obtengo cuando grabo el texto normal después de completar la extracción con Ghostscript (procesado solo con dos2unix):
grep -e '->abiog' ./rae-dos2unix.txt
->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-
Aquí es cuando se realizan los pasos anteriores (1-4) en el texto, al realizar el grepping obtuve:
grep -e '->abiog' ./rae-una-linea.txt
->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par- tiendo de materia inerte. 2. f. Bioquím. síntesis abiótica.
Respuesta1
Esto es bastante fácil en Perl. La opción de Perl -0
le indica que use caracteres NUL en lugar de nuevas líneas como separador de registros de entrada, por lo que, a menos que haya caracteres NUL en la entrada, tratará todo el archivo de entrada como un solo registro. Incluso si hay caracteres NUL, seguirá procesando registros posteriores, igual que el primero.
Nota: esto significa que todo el archivo de entrada debe caber en la memoria; en un sistema moderno con 16 GB o más de RAM, es poco probable que esto sea un problema. En un sistema antiguo con RAM insuficiente pero suficiente intercambio, seguirá funcionando pero será mucho más lento.
$ cat input.txt
->firstword: This is a defini-
tion.
->secondword: This is a second defini-
tion.
$ perl -0 -p -e 's/-\s*\n//g' input.txt
->firstword: This is a definition.
->secondword: This is a second definition.
Esto elimina todas las secuencias de guiones seguidos de cero o más espacios en blanco ( \s
, ver más abajo), seguidos de una nueva línea ( \n
).
La \s*
parte de la expresión regular está ahí para coincidir con los espacios en blanco finales quepodríaestar al final de una línea: en mi experiencia, es muy común que las líneas de texto tengan espacios en blanco al final (y son difíciles de detectar porque son caracteres que no se imprimen, es decir, invisibles). Alternativamente, use *
(cero o másespaciocaracteres) o [ \t]*
(cero o más espacios o tabulaciones) o \h*
(cero o máshorizontalcaracteres de espacio en blanco) en lugar de \s*
.
De man perlre
:
El conjunto de caracteres que se consideran espacios en blanco son aquellos que Unicode llama "Patrón de espacios en blanco", a saber:
U+0009 CHARACTER TABULATION U+000A LINE FEED U+000B LINE TABULATION U+000C FORM FEED U+000D CARRIAGE RETURN U+0020 SPACE U+0085 NEXT LINE U+200E LEFT-TO-RIGHT MARK U+200F RIGHT-TO-LEFT MARK U+2028 LINE SEPARATOR U+2029 PARAGRAPH SEPARATOR
NOTAS:
- Un
-
carácter no es el único carácter posible de "guión" o "guión" que puede estar en uso. Wikipedia tiene páginas que enumeran UnicodeGuiónyEstrellarsecaracteres. Afortunadamente, Perl tiene buenas capacidades de manejo de Unicode, por lo que el resumen se puede reescribir para usar\p{Dash}
(o\p{Pd}
) en lugar de-
hacer coincidir todos los caracteres de la categoría de guión:
$ perl -0 -p -e 's/\p{Dash}\h*\n//g' input.txt
->firstword: This is a definition.
->secondword: This is a second definition.
Sin embargo, esto tratará los guiones largos de la misma manera que los guiones (por lo que eliminará un guión largo al final de una línea, del mismo modo que lo haría con un guión)... y no es raro usar guiones largos en lugar de paréntesis. . Podrías utilizarlo \p{Hyphen}
en lugar de \p{Dash}
si no te importa, un mensaje de advertencia acerca de que el "guión" está en desuso. O podría usar una expresión entre corchetes que contenga solo los puntos del código Unicode que desea tratar como guiones, por ejemplo
perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g' input.txt
Recomiendo no tener cada definición de palabra comenzando con
->
. Eso hará que sea innecesariamente incómodo buscar una palabra con grep: la cadena de búsqueda tendrá que estar entre comillas (debido a>
, que el shell usa para la redirección) y precedida por--
(debido a-
; de lo contrario, grep tratará su patrón de búsqueda como si querías que fueran opciones). por ejemplo, no podrás hacer simplemente:grep ^firstword: dictionary.txt
En su lugar, tendrías que hacer:
grep -- '^->firstword:' dictionary.txt
Para un mejor ejemplo, extraje el texto de tu imagen contesseract-ocry ejecútelo a través de una versión del resumen de Perl que también elimina todas las líneas nuevas que no van seguidas de ->
:
$ cat input2.txt
->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
->abigeo. (Del lat. abigeus). 1. m. Am. Ladrén de ganado.
->abigotado, da. 1. adj. bigotudo.
->abinar. 1. tr. rur. y vulg. Binar la tierra.
->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia y
adjudicacion de bienes de quien muere sin testar.
Eiiftiénesis. (De a-2, bio- y -génesis). 1. f. Produccién hipotética de seres vivos par-
tiendo de materia inerte. 2. f. Bioquim. sintesis abistica,
->abidtico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. sintesis
abidtica
->abipon, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca del
Parana. U. t.c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familia
guaicurt hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, 0 en otros objetos.
->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice de
las zonas del mar profundo que se extienden mas alla del talud continental, y corresponden a
$ perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g; s/\n+(?!->)//g' input2.txt
->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
->abigeo. (Del lat. abigeus). 1. m. Am. Ladrén de ganado.
->abigotado, da. 1. adj. bigotudo.
->abinar. 1. tr. rur. y vulg. Binar la tierra.
->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia yadjudicacion de bienes de quien muere sin testar.Eiiftiénesis. (De a-2, bio- y -génesis). 1. f. Produccién hipotética de seres vivos partiendo de materia inerte. 2. f. Bioquim. sintesis abistica,
->abidtico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. sintesisabidtica
->abipon, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca delParana. U. t.c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familiaguaicurt hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, 0 en otros objetos.
->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice delas zonas del mar profundo que se extienden mas alla del talud continental, y corresponden a
Todavía recomiendo eliminar la ->
secuencia del archivo de salida final. Es un marcador útil mientras se procesa el texto, pero problemático después.
Un comentario de @zevzek resuelve el problema de "utiliza enormes cantidades de RAM". En lugar de utilizar NUL como separador de registros de entrada, utilícelo ->
como separador. Esto hace que el script Perl lea sólo la definición de una palabra a la vez, en lugar de todo el archivo a la vez. Esto hará que se ejecute mucho más rápido con un archivo de entrada muy grande porque no utilizará toda la RAM disponible y provocará que el sistema intercambie.
Se requieren otros cambios en el guión porque ahora estamos tratando la secuencia de caracteres que marca elcomienzode una nueva definición de palabra comofinde la definición anterior. Específicamente, ahora necesitamos:
- Cambie la opción de línea de comando
-p
(siempre generar el registro actual) a-n
(solo generar el registro actual cuando se lo indiquemos). - Elimine los caracteres de final de línea (
chomp()
la función de Perl hace esto) - Compruebe si el registro de entrada está vacío o contiene solo espacios en blanco porque ahora habrá unimaginarioregistro vacío antes del primer registro real "abigeato" y no queremos imprimirlo. (¿Por qué de repente aparece un registro vacío imaginario? Porque
->
ahora indica el final de un registro, no el comienzo de uno nuevo. La->
entrada->abigeato
es el separador entre el registro anterior (vacío) y el nuevo registro "abigeato") - imprima el registro modificado con "->" y una nueva línea.
En conjunto, estos cambiarían la frase final de esto:
$ perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g;
s/\n+(?!->)//g' input2.txt
a esto:
perl -n -e 'BEGIN { $/="->" };
chomp;
next if m/^\s*$/;
s/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g;
s/\n+//g;
print "->$_\n"' input2.txt
La salida de esta versión es la misma que la original, excepto que se garantiza que la línea de salida final terminará con una nueva línea ( \n
). El original no garantizaba esto; de hecho, lo impidió eliminando todas las nuevas líneas que no iban seguidas de ->
. Este es un bono gratuito porque técnicamente un archivo es solo un archivo de texto en Unix si cada línea termina con \n
.... la mayoría de las veces, esto no importa (al menos, no con las versiones modernas de las herramientas estándar de procesamiento de texto) , pero algunos programas no manejan correctamente la línea final de un "archivo de texto" si no termina en \n
.
(Por cierto, el original podría arreglarse agregando un bloque END para agregar una nueva línea al final de la salida END { print "\n" }
:)
$/
es una variable de Perl que define el separador de registros de entrada (consulte man perlvar
para obtener detalles sobre las variables predefinidas/especiales/de control de Perl), similar a la RS
variable en awk
. Anteriormente, estaba usando -0
la opción de Perl para configurarla en el carácter NUL (consulte man perlrun
para obtener detalles sobre las opciones de línea de comandos de Perl).
BEGIN
Las declaraciones ocurren una vez al comienzo de un script, antes y fuera del while(<>) { ..... }
bucle implícito causado por el uso de perl -p
u -n
opciones (que hacen que Perl se comporte como un superpoder sed
o sed -n
respectivamente). De manera similar, una END
declaración ocurre una vez al final de un script, después de que se hayan leído y procesado todas las entradas.
Respuesta2
Sugiero hacerlo en un solo script usando el N;P;D
patrón:
sed -e ':loop' -e '$!N;/\n->/!s/-*\n/ /;tloop' -e 'P;D'
Realiza un bucle para agregar la línea 'N'ext y eliminar las nuevas líneas con un guión opcional ( s/-*\n/ /
), hasta que la nueva línea comience con ->
.