2010-11-24 20 views

Respuesta

11

bien, si no te gusta la solución eval, he hackeado una máquina simple estado en Ruby para analizar simple "\ n" y "\ t" en correctamente las cadenas, incluyendo pre-e escalar de la barra invertida misma. Aquí está:

BACKSLASH = "\\" 

def unescape_c_string(s) 
    state = 0 
    res = '' 
    s.each_char { |c| 
     case state 
     when 0 
      case c 
      when BACKSLASH then state = 1 
      else res << c 
      end 
     when 1 
      case c 
      when 'n' then res << "\n"; state = 0 
      when 't' then res << "\t"; state = 0 
      when BACKSLASH then res << BACKSLASH; state = 0 
      else res << BACKSLASH; res << c; state = 0 
      end 
     end 
    } 
    return res 
end 

Ésta se puede ampliar fácilmente para soportar más caracteres, incluidas las entidades de varios caracteres, como \123. unidad de prueba para demostrar que funciona:

require 'test/unit' 

class TestEscapeCString < Test::Unit::TestCase 
    def test_1 
     assert_equal("abc\nasd", unescape_c_string('abc\nasd')) 
    end 
    def test_2 
     assert_equal("abc\tasd", unescape_c_string('abc\tasd')) 
    end 
    def test_3 
     assert_equal("abc\\asd", unescape_c_string('abc' + BACKSLASH * 2 + 'asd')) 
    end 
    def test_4 
     assert_equal("abc\\nasd", unescape_c_string('abc' + BACKSLASH * 2 + 'nasd')) 
    end 
    def test_5 
     assert_equal("abc\\\nasd", unescape_c_string('abc' + BACKSLASH * 3 + 'nasd')) 
    end 
    def test_6 
     assert_equal("abc\\\\nasd", unescape_c_string('abc' + BACKSLASH * 4 + 'nasd')) 
    end 
end 
3

Shorter, aún más hacky y bastante peligroso, debido a eval:

eval "\"#{string}\""
Un ejemplo sencillo:
 
> a = '1\t2\n3' 
> puts a 
1\t2\n3 
> puts eval "\"#{a}\"" 
1  2 
3 

+0

sí, que se me había ocurrido ... pero eval es el mal :-) – Simon

0

EDIT: Tenga en cuenta que esto no funciona realmente. Realmente necesitas construir un analizador apropiado aquí con una máquina de estado que rastrea si estás en una secuencia de escape o no.


Rubí es compatible con muchas de las mismas secuencias de escape, por lo que podría construir una tabla de traducción simple como esto:

T = { 
    '\n' => "\n", 
    '\t' => "\t", 
    '\r' => "\r" 
} 

Y luego usar esa tabla de traducción para sustituir esas secuencias en la cadena de origen:

a = '1\t2\n3' 

a.gsub(/#{T.keys.map(&Regexp.method(:escape)).join('|')}/, &T.method(:[])) 
# => "1\t2\n3" 
+4

No va a funcionar bien; El análisis de las construcciones "\ n" es un poco más difícil que solo buscar y reemplazar: primero hay que buscar escapes de secuencias de escape. De hecho, es mucho más fácil hacerlo yendo una línea, byte a byte. – GreyCat

+0

¡Pero me gusta lo que estás haciendo con 'T'! – Ashe

Cuestiones relacionadas