Есть ли в Ruby какой-либо встроенный метод для экранирования и деэкранирования строк? В прошлом я использовал регулярные выражения; однако мне пришло в голову, что Ruby, вероятно, постоянно выполняет такие преобразования внутри. Возможно, эта функциональность где-то раскрыта.
На данный момент я придумал эти функции. Они работают, но выглядят несколько халтурно:
def escape(s)
s.inspect[1..-2]
end
def unescape(s)
eval %Q{"#{s}"}
end
Есть ли лучший способ?
Существует множество методов бегства, некоторые из них:
# 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\""
Функция Калеб был ближе всего к оборотной строкой #проверить мне удалось найти, однако в нем содержатся две ошибки:
Я исправил вышеуказанные ошибки и это обновленная версия:
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
Обновление: Я больше не согласен со своим ответом, но предпочел бы не удалять его, так как подозреваю, что другие могут пойти по этому неверному пути, и уже было много обсуждений этого ответа и его альтернатив, так что я думаю, что он все еще вносит свой вклад в разговор, но, пожалуйста, не используйте этот ответ в реальном коде.
Если вы не хотите использовать eval
, но готовы использовать модуль YAML
, вы можете использовать его вместо этого:
require 'yaml'
def unescape(s)
YAML.load(%Q(---\n"#{s}"\n))
end
Преимущество YAML
перед eval
заключается в том, что он предположительно более безопасен. В cane
запрещено любое использование eval
. Я встречал рекомендации использовать $SAFE
вместе с eval
, но в настоящее время это недоступно в JRuby.
Что касается Python, то в нем есть встроенная поддержка unescaping backslashes.
В этом может помочь программа Ruby'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
Мне не очень нравится делать это таким образом. Это скорее любопытство, чем то, что я бы сделал на практике.
И YAML'ы ::раскодировал
не'т, кажется, чтобы защитить кавычки, например, '
и в "
. Я'м предполагаем, что это дизайн, но это заставляет меня грустить.
Вы определенно не хотите использовать функции "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
Рубиновая 2.5 добавлено строка#undump
в дополнение к строка#свалка
:
$ 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 \" \\"
Я подозреваю, что `Shellwords.побег будем делать то, что вы'вновь ищу
https://ruby-doc.org/stdlib-1.9.3/libdoc/shellwords/rdoc/Shellwords.html#method-c-shellescape