2011-04-19 10 views
7

Tengo una expresión regular en Ruby que no funciona correctamente en el modo multilínea.¿Cómo soluciono esta expresión regular de varias líneas en Ruby?

Estoy tratando de convertir texto de reducción en el marcado Text-eque utilizado en Redmine. El problema está en mi expresión regular para convertir bloques de código. Debe encontrar las líneas que conducen con 4 espacios o una pestaña, luego envuélvalos en pre etiquetas.

markdownText = '# header 

some text that precedes code 

    var foo = 9; 
    var fn = function() {} 

    fn(); 

some post text' 

puts markdownText.gsub!(/(^(?:\s{4}|\t).*?$)+/m,"<pre>\n\\1\n</pre>") 

resultado previsto:

# header 

some text that precedes code 

<pre> 
    var foo = 9; 
    var fn = function() {} 

    fn(); 
</pre> 

some post text 

El problema es que el cierre pre etiqueta se imprime al final del documento en lugar de después de "fn();". Probé algunas variantes de la siguiente expresión, pero no coincide:

gsub!(/(^(?:\s{4}|\t).*?$)+^(\S)/m, "<pre>\n\\1\n</pre>\\2") 

¿Cómo consigo la expresión regular para que coincida con sólo el bloque de código sangrado? Puede probar esta expresión regular en Rubular here.

+1

por qué no incluir nueva línea en su expresión regular: '((:?.? \ S {4} | t \) * \ n) +' –

+0

posible duplicado de [partidos RegEx etiquetas de apertura, excepto XHTML auto-contenido tags] (http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags) –

+0

@Mladen Jablanovic No pude conseguir que tu ejemplo funcione con este código: 'puts markdownText.gsub! (/ ((?: \ s {4} | \ t). *? \ n) + /,"

\n\\1\n
")'. ¿Cómo se comportaría '\ n' de forma diferente a' $ '? – DonovanChan

Respuesta

12

En primer lugar, tenga en cuenta que 'm' modo multilínea en Ruby es equivalente a 's' modo de una sola línea de otros idiomas. En otras palabras; El modo 'm' en Ruby significa: "punto coincide con todos".

Esta expresión regular va a hacer un buen trabajo de hacer coincidir una sección de código de reducción del precio similar:

re =/# Match a MARKDOWN CODE section. 
    (\r?\n)    # $1: CODE must be preceded by blank line 
    (     # $2: CODE contents 
     (?:    # Group for multiple lines of code. 
     (?:\r?\n)+  # Each line preceded by a newline, 
     (?:[ ]{4}|\t).* # and begins with four spaces or tab. 
    )+     # One or more CODE lines 
     \r?\n    # CODE folowed by blank line. 
    )     # End $2: CODE contents 
    (?=\r?\n)   # CODE folowed by blank line. 
    /x 
result = subject.gsub(re, '\1<pre>\2</pre>') 

Esto requiere una línea en blanco antes y después de la sección de código y permite líneas en blanco dentro de la misma sección de código . Permite terminaciones de línea \r\n o \n. Tenga en cuenta que esto no elimina los 4 espacios principales (o tabulación) antes de cada línea. Hacer eso requerirá más complejidad de código. (No soy un tipo ruby, así que no puedo ayudar con eso.)

Recomendaría consultar la fuente de reducción en sí para ver cómo se está haciendo realmente.

+0

Gracias por los comentarios detallados ridgerunner. Creo que la tuya fue la única respuesta hasta ahora que realmente funcionó a mis especificaciones de la caja. – DonovanChan

0

/^(\s{4}|\t)+.+\;\n$/m

funciona un poco mejor, todavía recoge una nueva línea que no queremos. here está en rubular.

+0

vio la publicación de ridgerunner después de publicar esto, definitivamente una mejor respuesta. –

0

Here 's otro que capta todas las líneas con sangría en un solo bloque

((?:^(?: {4}|\t)[^\n]*$\n?)+) 
0

Esto es trabajo para mí con su entrada de la muestra.

markdownText.gsub(/\n?((\s{4}.+)+)/, "\n<pre>#{$1}\n</pre>") 
Cuestiones relacionadas