2009-06-05 20 views
9

Estoy tratando de crear un sistema de envoltura de palabras sueltas a través de una expresión regular en Perl. Lo que me gustaría es aproximadamente cada 70 caracteres para verificar el próximo espacio en blanco y reemplazar ese espacio con una línea nueva, y luego hacer esto para toda la cadena. La cadena en la que estoy trabajando ya puede tener líneas nuevas, pero la cantidad de texto entre líneas nuevas suele ser muy larga.¿Cómo puedo encapsular una cadena en Perl?

Me gustaría evitar el bucle de un carácter a la vez o usar substr si puedo, y preferiría editar esta cadena en lugar de crear nuevos objetos de cadena. Estas son sólo preferencias, sin embargo, y si no puedo lograr lo que estoy buscando sin romper estas preferencias, está bien.

¿Pensamientos?

+1

En lugar de espacios en blanco, hay un juego de caracteres denotado por \ b que coincide con los límites de palabras que pueden ser un poco más robustos. – jiggy

+2

@jiggy \ b no es una clase de caracteres, es una aserción de ancho cero. –

+2

Además, "enfáticamente!"podría romperse entre la palabra una puntuación, y eso está mal ! – Axeman

Respuesta

11
s/(.{70}[^\s]*)\s+/$1\n/ 

Consumir los primeros 70 caracteres, luego detenerse en el siguiente espacio en blanco, capturando todo en el proceso. Luego, emita la cadena capturada, omitiendo el espacio en blanco al final, agregando una nueva línea.

Esto no garantiza que sus líneas se corten estrictamente a 80 caracteres o algo así. No hay garantía de que la última palabra que consume no tendrá mil millones de caracteres.

+1

Creo que sería mejor que. {70,80} \ s +, de modo que si obtienes" como en un "comenzando con el espacio en 71, obtienes una envoltura más ajustada. – Axeman

+0

@Axeman es correcto, pero gracias a la evaluación ambiciosa (que trata de hacer coincidir tanto contenido como sea posible), quieres. {1,70} para una longitud de línea de 70 caracteres. He editado la respuesta para hacer esto. –

+1

Una expresión regular más avanzada, que puede manejar correctamente los saltos de línea (en lugar de matarlos como lo hace el ejemplo básico anterior) sería 's/(. {1,70} | \ S {71,}) (?: \ s [^ \ S \ r \ n] * | \ Z)/$ 1 \ n/g'. Quería mantener la respuesta oficial simple, así que lo dejé. –

22

Mire módulos como Text::Wrap o Text::Autoformat.

Dependiendo de sus necesidades, incluso el pliegue de la utilidad del núcleo GNU (1) puede ser una opción.

+1

Esa es probablemente la mejor manera, excepto para algunos de la sintaxis arcaica. – Axeman

+0

En realidad, acabo de encontrar que Text :: Wrap :: Smart deja de romper una línea si hay una palabra longe r que el tamaño del mensaje definido. – RushPL

7

La respuesta de Welbog se ajusta al primer espacio después de 70 caracteres. Esto tiene el defecto de que las palabras largas que comienzan cerca del final de la línea forman una línea demasiado larga. Yo sugeriría que en vez de envolver en el último espacio dentro de los primeros, por ejemplo, 81 caracteres, o envolviendo en el primer espacio si tiene un carácter "palabra"> 80, de manera que sólo las líneas realmente irrompibles son demasiado largo:

s/(.{1,79}\S|\S+)\s+/$1\n/g; 

en perl moderna:

s/(?:.{1,79}\S|\S+)\K\s+/\n/g; 
+1

D'oh! E incluso he hecho este tipo de cosas en numerosas ocasiones. – Axeman

5

Usted puede conseguir mucho, mucho más control y fiabilidad mediante el uso de Text::Format

use Text::Format; 
print Text::Format->new({columns => 70})->format($text); 
1

Esta es la que he utilizado siempre.

A diferencia de la solución aceptada, se ajustará ANTES de la longitud del wrap-length (en este caso, 75 caracteres), a menos que haya una cadena realmente larga (como una URL), en cuyo caso simplemente colocará esa cadena en su propia línea, en lugar de romperla.

s/(?=.{70,})(.{0,70}\n?)()/\1\2\n /g 

Esta segunda forma se encarga de todos los finales de línea: Mac \ r, Unix \ n, Windows \ r \ n, y teletipo \ n \ r, pero que uno se utiliza como un sustituto todavía depende de lo que se pone en la cláusula de reemplazo: he usado \ n.

s/(?=.{70,})(.{0,70}(?:\r\n?|\n\r?)?)()/\1\2\n /g 

Ambas versiones también sangría a todas las líneas ajustadas después de la primera por un espacio: eliminar el espacio antes de la última/g si no quiere eso, pero por lo general les resulta más agradable.

Cuestiones relacionadas