Iniciar sesión

Ver la versión completa : Herramienta para formatear ficheros de texto plano



OscarBraindeaD
21/08/2019, 15:45
Hola a todos.
Quiero formatear una serie de textos en ficheros de texto plano, algunos más largos que otros, para que cada línea termine con un punto. Si, además, se consigue que la línea tenga una longitud mínima (aunque hubiera 2 frases terminadas con punto en la misma línea) sería ya perfecto.
Por ejemplo, dado este texto:


Y las formas angélicas convertíanse en insignificantes espectros con cabeza de luego,
y claramente comprendí que no debía esperar auxilio alguno. Entonces, como una
magnífica nota musical, se insinuó en mi imaginación la idea del inefable reposo que
nos espera en la tumba. Llegó suave, furtivamente. Sospecho que necesité un gran
rato para apreciarla por completo. Pero en el preciso instante en que mi espíritu
comenzaba a sentir claramente esa idea, y a acariciarla, las figuras de los jueces se
desvanecieron como por arte de magia. Los hachones se redujeron a la nada. Sus
luces se apagaron por completo, y sobrevino la negrura de las tinieblas. Todas las
sensaciones fingieron desaparecer como en una zambullida loca y precipitada del
alma en el Hades. Y el Universo fue sólo noche, silencio, quietud.
Estaba desvanecido. Pero, sin embargo, no puedo decir que hubiese perdido la
conciencia del todo. La que me quedaba, no intentaré definirlo. Ni describirlo
siquiera. Pero, en fin, todo no estaba perdido. En medio del más profundo sueño…,
¡no! En medio del delirio…, ¡no! En medio del desvanecimiento…, ¡no! En medio de
la muerte…, ¡no! Si fuera de otro modo, no habría salvación para el hombre. Cuando
nos despertamos del más profundo sueño, rompemos la telaraña de algún sueño. Y,
no obstante, un segundo más tarde es tan delicado este tejido, que no recordamos
haber soñado.


querría convertirlo en algo como:


Y las formas angélicas convertíanse en insignificantes espectros con cabeza de luego, y claramente comprendí que no debía esperar auxilio alguno.
Entonces, como una magnífica nota musical, se insinuó en mi imaginación la idea del inefable reposo que nos espera en la tumba.
Llegó suave, furtivamente. Sospecho que necesité un gran rato para apreciarla por completo.
Pero en el preciso instante en que mi espíritu comenzaba a sentir claramente esa idea, y a acariciarla, las figuras de los jueces se desvanecieron como por arte de magia.
Los hachones se redujeron a la nada. Sus luces se apagaron por completo, y sobrevino la negrura de las tinieblas.
Todas las sensaciones fingieron desaparecer como en una zambullida loca y precipitada del alma en el Hades.
Y el Universo fue sólo noche, silencio, quietud. Estaba desvanecido. Pero, sin embargo, no puedo decir que hubiese perdido la conciencia del todo.
La que me quedaba, no intentaré definirlo. Ni describirlo siquiera. Pero, en fin, todo no estaba perdido.
En medio del más profundo sueño…, ¡no! En medio del delirio…, ¡no! En medio del desvanecimiento…, ¡no!
En medio de la muerte…, ¡no! Si fuera de otro modo, no habría salvación para el hombre.
Cuando nos despertamos del más profundo sueño, rompemos la telaraña de algún sueño. Y, no obstante, un segundo más tarde es tan delicado este tejido, que no recordamos haber soñado.

¿Se os ocurre algún maquinillo que lo haga de una forma más o menos automática? Si no, trataré de hacerme un script que lo apañe...

Muchas gracias!

swapd0
21/08/2019, 15:59
A mi solo se me ocurre con un script/programa.

OscarBraindeaD
21/08/2019, 16:24
A mi solo se me ocurre con un script/programa.

Sí, algo que exista ya es un poco rebuscado pero había que intentarlo... luego trataré de hacer algo, a ver qué saco =)

Trenz
21/08/2019, 20:52
Por si usas Linux o similar, fold y fmt sirven para reformatear un texto cambiando la anchura de las líneas, pero no hay ninguna utilidad que sirva para hacer lo que planteas. Con AWK (lenguaje de script clásico para procesar textos) lo de formatear por oraciones es lo suficientemente simple como para resolverlo en una línea:



awk 'BEGIN {RS="[.]( *|\n)"} {gsub(" *\n *"," "); print $0 "."}' texto.txt > texto_formateado.txt


Añadiendo el requisito de que las líneas tengan una longitud mínima la cosa se complica. El script que se me ocurre sería:



BEGIN {
line_len = 80 # longitud minima
RS="[.]( *|\n)"
}
{
gsub(" *\n *"," ")
if (line == "")
line = $0 "."
else
line = line " " $0 "."
if (length(line) >= line_len) {
print line
line = ""
}
}
END {
if (line != "")
print line
}


A ejecutar:



awk -f script.awk texto.txt > texto_formateado.txt

tognin
21/08/2019, 23:58
Notepad++ es tu amigo.

tiene una potente herramienta de sustitucion que quizas te sirva.

slaudos

OscarBraindeaD
22/08/2019, 06:31
Por si usas Linux o similar, fold y fmt sirven para reformatear un texto cambiando la anchura de las líneas, pero no hay ninguna utilidad que sirva para hacer lo que planteas. Con AWK (lenguaje de script clásico para procesar textos) lo de formatear por oraciones es lo suficientemente simple como para resolverlo en una línea:



awk 'BEGIN {RS="[.]( *|\n)"} {gsub(" *\n *"," "); print $0 "."}' texto.txt > texto_formateado.txt


Añadiendo el requisito de que las líneas tengan una longitud mínima la cosa se complica. El script que se me ocurre sería:



BEGIN {
line_len = 80 # longitud minima
RS="[.]( *|\n)"
}
{
gsub(" *\n *"," ")
if (line == "")
line = $0 "."
else
line = line " " $0 "."
if (length(line) >= line_len) {
print line
line = ""
}
}
END {
if (line != "")
print line
}


A ejecutar:



awk -f script.awk texto.txt > texto_formateado.txt


Muchas gracias, Trenz, luego en el trabajo lo pruebo que ahí tengo un linux... tengo la espinita clavada de aprender awd, sed y todas esas cosas pero me come el día a día y nunca saco tiempo.

-----Actualizado-----


Notepad++ es tu amigo.

tiene una potente herramienta de sustitucion que quizas te sirva.

slaudos

Gracias Tognin, lo intenté usando macros de Notepad++ pero no lo logré. Si no lo consigo con los scripts de Trenz, intentaré de nuevo con la sustitución de Notepad++.

Trenz
22/08/2019, 13:54
Muchas gracias, Trenz, luego en el trabajo lo pruebo que ahí tengo un linux... tengo la espinita clavada de aprender awd, sed y todas esas cosas pero me come el día a día y nunca saco tiempo.

Hmmm, si los ficheros de texto proceden de Windows los finales de línea van a ser '\r\n' (los caracteres ASCII retorno de carro y nueva línea) en lugar de sólo '\n'. No conté con eso. Una forma de solucionarlo al vuelo sin tocar el script es quitar el '\r' antes de formatear y añadirlo después:



sed 's/\r$//' texto.txt | awk -f script.awk | sed 's/$/\r/' > texto_formateado.txt

juanvvc
22/08/2019, 18:00
Otra opción: https://vi.stackexchange.com/questions/2846/how-to-set-up-vim-to-work-with-one-sentence-per-line

Siguiendo esa misma idea, podrías probar:



sed ':a;{N;s/\n/ /;ba}' texto.txt | sed 's/\([\.!?]\)/\1\n/g' | sed 's/^\s*//'




Y las formas angélicas convertíanse en insignificantes espectros con cabeza de luego, y claramente comprendí que no debía esperar auxilio alguno.
Entonces, como una magnífica nota musical, se insinuó en mi imaginación la idea del inefable reposo que nos espera en la tumba.
Llegó suave, furtivamente.
Sospecho que necesité un gran rato para apreciarla por completo.
Pero en el preciso instante en que mi espíritu comenzaba a sentir claramente esa idea, y a acariciarla, las figuras de los jueces se desvanecieron como por arte de magia.
Los hachones se redujeron a la nada.
Sus luces se apagaron por completo, y sobrevino la negrura de las tinieblas.
Todas las sensaciones fingieron desaparecer como en una zambullida loca y precipitada del alma en el Hades.
Y el Universo fue sólo noche, silencio, quietud.
Estaba desvanecido.
Pero, sin embargo, no puedo decir que hubiese perdido la conciencia del todo.
La que me quedaba, no intentaré definirlo.
Ni describirlo siquiera.
Pero, en fin, todo no estaba perdido.
En medio del más profundo sueño…, ¡no!
En medio del delirio…, ¡no!
En medio del desvanecimiento…, ¡no!
En medio de la muerte…, ¡no!
Si fuera de otro modo, no habría salvación para el hombre.
Cuando nos despertamos del más profundo sueño, rompemos la telaraña de algún sueño.
Y, no obstante, un segundo más tarde es tan delicado este tejido, que no recordamos haber soñado.

Trenz
22/08/2019, 21:09
Siguiendo esa misma idea, podrías probar:



sed ':a;{N;s/\n/ /;ba}' texto.txt | sed 's/\([\.!?]\)/\1\n/g' | sed 's/^\s*//'



Está claro que me obcequé con el punto XD. La solución que planteaba en AWK no sirve si se quieren tener en cuenta los signos de cierre de interrogación y exclamación. Así que es mejor lo que propones. Y no dejan de ser soluciones toscas, que siempre se pueden mejorar, claro. Pero para hacerlo realmente bien habría que usar una librería de procesado de lenguaje natural.

OscarBraindeaD
23/08/2019, 07:21
Hola a todos, probé los scripts que puso Trenz al inicio y funcionan realmente bien. Pero al pasarlo a windows, se descabalaba todo con los saltos de línea. Acabo de leer vuestros comentarios avisando precisamente de eso :)
Al final lo que hice fue una macro de editplus que, primero ponía todo el texto en una única línea y, volviendo al inicio del texto, otra macro que buscase puntos y saltase de línea al encontrarlo. Luego ha habido bastante trabajo manual para exclamaciones, puntos suspensivos, etc.
Perdonad que no comentase que era para windows y muchas gracias por vuestros scripts, ideas y soluciones. Me los guardo porque nos necesitaré en breve otra vez y lo que proponéis me ahorrará mucho curro. Los textos de esta remesa eran las "narraciones extraordinarias" de Edgar Allan Poe. He hecho una pequeña aplicación en android que los lee y los narra (con la voz del GPS). Eran textos más o menos cortos y no ha sido excesivamente doloroso. Quiero hacer lo mismo con alguna novela de Poe (aventuras de Arthur Gordon Pym) y relatos y novelas de Lovecraft, que de media tienen más longitud y hacerlo con la macro puede ser doloroso, así que probaré las correcciones que proponéis a los scripts originales.
Muchas gracias de nuevo a todos!

Trenz
23/08/2019, 16:58
Lo que hiciste al final es similar a lo que propone Juanvvc: con la primera invocación de sed junta todo el texto en una única línea y con la segunda introduce saltos de línea después de cada punto, cierre de interrogación o cierre de exclamación. De todas formas, ninguno de esos signos de puntuación finalizan siempre una oración, como sucede con el punto en el caso de las abreviaturas. Se puede afinar más la expresión regular para tener en cuenta si lo que sigue parece el inicio de otra oración: una letra mayúscula precedida opcionalmente por '¿' o '¡'. Es decir, sería: sed -E 's/([.?!])\s+([¿¡]?[A-Z])/\1\n\2/g'. Probablemente funcione en la mayoría de los casos, pero seguirá fallando en algunos. En realidad es un problema que pertenece al ámbito del procesado de lenguaje natural. Echando un vistazo rápido, parece que una de las librerías de ese tipo más populares es NLTK para Python. No creo que sea difícil montar una solución por esa vía.

Trenz
24/08/2019, 16:52
Por si te vuelves a poner con el tema... Acabo de estar viendo algunos ejemplos de uso de NLTK y haciendo algunas pruebas, ya que me picó la curiosidad. Te dejo el script en Python. Tendrías que instalar la librería NLTK (https://www.nltk.org/install.html) y el segmentador punkt (https://raw.githubusercontent.com/nltk/nltk_data/gh-pages/packages/tokenizers/punkt.zip) (yo simplemente cojo el fichero PY3/spanish.pickle y lo cargo desde el directorio de trabajo).



import sys
import nltk.data

LONG_MIN = 0 # longitud minima de las lineas de salida

with open(sys.argv[1], 'r') as file:
texto = file.read().replace('\n', ' ')

tokenizer = nltk.data.load('./spanish.pickle')
oraciones = tokenizer.tokenize(texto)

linea = ''
for oracion in oraciones:
linea += (' ' if linea else '') + oracion
if len(linea) >= LONG_MIN:
print('{}'.format(linea))
linea = ''
if linea:
print('{}'.format(linea))


Con este texto de ejemplo



Tome Ud. Alejando lo cogió. Tome, Sr. García. 1724 fue el año en que sucedió. Tú
dijiste que habías visto a... ¿a quién?, que no lo recuerdo. Ana, María... Yo
qué sé cómo se llamaba. ¿Tanto te interesa? ¡Qué alegre estaba!, ¡cómo se
puso!, ¡qué brincos dio! ¡Fue una gran noticia!


Con la expresión regular que comentaba antes se obtiene:



Tome Ud.
Alejando lo cogió.
Tome, Sr.
García. 1724 fue el año en que sucedió.
Tú dijiste que habías visto a... ¿a quién?, que no lo recuerdo.
Ana, María...
Yo qué sé cómo se llamaba.
¿Tanto te interesa?
¡Qué alegre estaba!, ¡cómo se puso!, ¡qué brincos dio!
¡Fue una gran noticia!


Como era de esperar, falla en "Sr. García" y "García. 1724". El script que usa NLTK lo hace bien:



Tome Ud.
Alejando lo cogió.
Tome, Sr. García.
1724 fue el año en que sucedió.
Tú dijiste que habías visto a... ¿a quién?, que no lo recuerdo.
Ana, María...
Yo qué sé cómo se llamaba.
¿Tanto te interesa?
¡Qué alegre estaba!, ¡cómo se puso!, ¡qué brincos dio!
¡Fue una gran noticia!