Pequeñas delicias de las expresiones regulares

Posted: June 13th, 2009 | Author: FreedomCoder | Filed under: Open Source, Programming, how-to | Tags: , , , | No Comments »

Como les conté acáacá, estoy escribiendo un tokenizador para un wiki que estoy programando. Y hoy me encontré con una cosa muy extraña de las expresiones regulares.
En ruby la función match sirve para buscar el primer match de una regex dentro de un string. Por ejemplo (usando el irb):

irb(main):001:0> m = /a/.match "babab"
=> #<MatchData "a">
irb(main):002:0> m.pre_match
=> "b"
irb(main):003:0> m[0]
=> "a"

En particular, el pre_match es lo que está antes del match en el string. También según había entendido (mal) /\Z/ matchea con el final del string. Por ejemplo:

irb(main):004:0> m = /\Z/.match "hola"
=> #<MatchData "">
irb(main):005:0> m.pre_match
=> "hola"
Pero, /\Z/ tiene un comportamiento muy extraño, aunque documentado, cuando el último caracter antes del final es un \n. Lo que pasa es que el pre_match queda ¡sin el\n del final!. Lo muestro en el irb:
irb(main):006:0> m = /\Z/.match "\n"
=> #<MatchData "">
irb(main):007:0> m.pre_match
=> ""

Para que no se manduque el \n, hay que usar /\z/ (¡en minúscula!):

irb(main):008:0> m = /\z/.match "\n"
=> #<MatchData "">
irb(main):009:0> m.pre_match
=> "\n"

Por lo tanto tuve que tocar el tokenizer, ahora la función de initialize quedó así (miren el cambio de la "Z" a "z"):

    def initialize( delimiters )
      @delimiter_list = [[/\z/, :finish]] +
        delimiters.to_a.map { |k,arr| arr.map { |re| [re, k] } }.inject([]) { |ac,ps| ac + ps }
      @match_cache = nil
    end

Y el test que captura el problema que genera usar \Z en vez de \z quedó así:

  def test_carriage_return_ending
    tok = Tokenizer.new( :a_kind => [/!/] )
    tok.source = "bang!\n"
    tok.next_token
    assert_equal true, tok.has_next?
    tok.next_token
    assert_equal true, tok.has_next?
    assert_equal "\n", tok.next_token[0].to_s
    assert_equal false, tok.has_next?
  end

Happy hacking,

Aureliano.

(Via aurelianito.) Original Link: Pequeñas delicias de las expresiones regulares