Il modo migliore per sfuggire e scontrare le stringhe in Ruby?

Ruby ha un metodo integrato per eseguire l’escape e le stringhe di escape? In passato, ho usato espressioni regolari; tuttavia, mi viene in mente che Ruby probabilmente esegue internamente tali conversioni. Forse questa funzionalità è esposta da qualche parte.

Finora ho trovato queste funzioni. Funzionano, ma sembrano un po ‘hacky:

def escape(s) s.inspect[1..-2] end def unescape(s) eval %Q{"#{s}"} end 

C’è un modo migliore?

Se non vuoi usare eval , ma sei disposto a usare il modulo YAML , puoi invece usarlo:

 require 'yaml' def unescape(s) YAML.load(%Q(---\n"#{s}"\n)) end 

Il vantaggio di YAML rispetto a eval è che è presumibilmente più sicuro. cane non consente l’uso di eval . Ho visto consigli per utilizzare $SAFE insieme a eval , ma al momento non è disponibile tramite JRuby.

Per quel che vale, Python ha il supporto nativo per i backslash senza escape .

Ci sono un sacco di metodi di fuga, alcuni di loro:

 # Regexp escapings >> Regexp.escape('\*?{}.') => \\\*\?\{\}\. >> URI.escape("test=100%") => "test=100%25" >> CGI.escape("test=100%") => "test%3D100%25" 

Quindi, dipende in realtà dal problema che devi risolvere. Ma eviterei di usare ispezionare per fuggire.

Aggiornamento: c’è un dump, ispeziona, e sembra che sia quello di cui hai bisogno:

 >> "\n\t".dump => "\"\\n\\t\"" 

La funzione Caleb era la cosa più vicina al contrario di String #inspect che ero in grado di trovare, tuttavia conteneva due bug:

  • \\ non è stato gestito correttamente.
  • \ x .. mantenuto il backslash.

Ho corretto i bug di cui sopra e questa è la versione aggiornata:

 UNESCAPES = { 'a' => "\x07", 'b' => "\x08", 't' => "\x09", 'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c", 'r' => "\x0d", 'e' => "\x1b", "\\\\" => "\x5c", "\"" => "\x22", "'" => "\x27" } def unescape(str) # Escape all the things str.gsub(/\\(?:([#{UNESCAPES.keys.join}])|u([\da-fA-F]{4}))|\\0?x([\da-fA-F]{2})/) { if $1 if $1 == '\\' then '\\' else UNESCAPES[$1] end elsif $2 # escape \u0000 unicode ["#$2".hex].pack('U*') elsif $3 # escape \0xff or \xff [$3].pack('H2') end } end # To test it while true line = STDIN.gets puts unescape(line) end 

YAML’s ::unescape non sembra sfuggire ai caratteri delle virgolette, ad esempio ' e " . Sto supponendo che sia di progettazione, ma mi rende triste.

Sicuramente non vuoi usare eval su dati arbitrari o forniti dal cliente.

Questo è quello che uso. Gestisce tutto ciò che ho visto e non introduce alcuna dipendenza.

 UNESCAPES = { 'a' => "\x07", 'b' => "\x08", 't' => "\x09", 'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c", 'r' => "\x0d", 'e' => "\x1b", "\\\\" => "\x5c", "\"" => "\x22", "'" => "\x27" } def unescape(str) # Escape all the things str.gsub(/\\(?:([#{UNESCAPES.keys.join}])|u([\da-fA-F]{4}))|\\0?x([\da-fA-F]{2})/) { if $1 if $1 == '\\' then '\\' else UNESCAPES[$1] end elsif $2 # escape \u0000 unicode ["#$2".hex].pack('U*') elsif $3 # escape \0xff or \xff [$3].pack('H2') end } end 

L’ inspect di Ruby può aiutare:

  "a\nb".inspect => "\"a\\nb\"" 

Normalmente se stampiamo una stringa con un line-feed incorporato, otterremmo:

 puts "a\nb" a b 

Se stampiamo la versione controllata:

 puts "a\nb".inspect "a\nb" 

Assegna la versione controllata a una variabile e avrai la versione di escape della stringa.

Per annullare l’escaping, eval la stringa:

 puts eval("a\nb".inspect) a b 

Non mi piace davvero farlo in questo modo. È più una curiosità che qualcosa che farei in pratica.

Sospetto che Shellwords.escape farà ciò che stai cercando

https://ruby-doc.org/stdlib-1.9.3/libdoc/shellwords/rdoc/Shellwords.html#method-c-shellescape