Лучший способ избежать и убрать строки в Ruby? - PullRequest
25 голосов
/ 27 декабря 2011

Есть ли в Ruby какой-либо встроенный метод для экранирования строк и ?В прошлом я использовал регулярные выражения;однако мне приходит в голову, что Ruby, вероятно, постоянно делает такие преобразования внутренне.Возможно, эта функциональность где-то раскрыта.

До сих пор я придумал эти функции.Они работают, но кажутся немного хакерскими:

def escape(s)
  s.inspect[1..-2]
end

def unescape(s)
  eval %Q{"#{s}"}
end

Есть ли лучший способ?

Ответы [ 7 ]

15 голосов
/ 28 февраля 2014

Функция Caleb была ближайшей к противоположности String #inspect, которую мне удалось найти, однако она содержала две ошибки:

  • \\ была обработана неправильно.
  • \ x .. сохранил обратную косую черту.

Я исправил вышеуказанные ошибки, и это обновленная версия:

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
15 голосов
/ 27 декабря 2011

Существует множество методов экранирования, некоторые из них:

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

Итак, это действительно зависит от проблемы, которую вам нужно решить.Но я бы избегал использовать inspect для экранирования.

Обновление - есть дамп, inspect использует его, и, похоже, это то, что вам нужно:

>> "\n\t".dump
=> "\"\\n\\t\""
13 голосов
/ 12 сентября 2013

Обновление : я больше не согласен с моим собственным ответом, но я бы предпочел не удалять его, так как подозреваю, что другие могут пойти по этому неправильному пути, и уже было много обсуждений этот ответ и его альтернативы, поэтому я думаю, что он все еще способствует разговору, но, пожалуйста, не используйте этот ответ в реальном коде.

Если вы не хотите использовать eval, но готовы использовать модуль YAML, вы можете использовать его вместо:

require 'yaml'

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

Преимущество перед YAML перед eval заключается в том, что оно предположительно безопаснее. cane запрещает любое использование eval. Я видел рекомендации по использованию $SAFE вместе с eval, но в данный момент он недоступен через JRuby.

Что бы это ни стоило, в Python есть встроенная поддержка неэкранированных обратных косых черт .

11 голосов
/ 27 декабря 2011

Ruby's inspect может помочь:

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

Обычно, если мы напечатаем строку со встроенным переводом строки, мы получим:

puts "a\nb"
a
b

Если мы напечатаемпроверенная версия:

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

Назначьте проверенную версию переменной, и у вас будет экранированная версия строки.

Чтобы отменить экранирование, eval строка:

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

Мне не очень нравится так делать.Это скорее любопытство, чем то, что я бы делал на практике.

10 голосов
/ 22 ноября 2013

YAML ::unescape, по-видимому, не содержит кавычек, например, ' и ".Я предполагаю, что это из-за дизайна, но это меня огорчает.

Вы определенно не хотите использовать eval для произвольных или предоставленных клиентом данных.

Это то, что я использую,Обрабатывает все, что я видел, и не вводит никаких зависимостей.

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
7 голосов
/ 16 ноября 2018

Ruby 2.5 добавлено String#undump в качестве дополнения к String#dump:

$ irb
irb(main):001:0> dumped_newline = "\n".dump
=> "\"\\n\""
irb(main):002:0> undumped_newline = dumped_newline.undump
=> "\n"

С ним:

def escape(s)
  s.dump[1..-2]
end

def unescape(s)
  "\"#{s}\"".undump
end

$irb
irb(main):001:0> escape("\n \" \\")
=> "\\n \\\" \\\\"
irb(main):002:0> unescape("\\n \\\" \\\\")
=> "\n \" \\"
4 голосов
/ 22 октября 2016

Я подозреваю, что Shellwords.escape сделает то, что вы ищете

https://ruby -doc.org / STDLIB-1.9.3 / libdoc / shellwords / RDoc / Shellwords.html # способ-с-shellescape

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...