Я пытаюсь очистить некоторый автоматически сгенерированный код, где фрагменты входного URL:
- могут содержать пробелы, которые должны быть
%
-экранированы (как %20
, а не *) 1006 *) - может включать в себя другие недействительные символы URL, которые также должны быть
%
-экранированы - , могут включать разделители пути, которые необходимо оставить в покое (
/
) - может включать в себя уже экранированные компоненты, для которых необходимо , а не , чтобы экранироваться дважды
В существующем коде используется libcurl
(через Typhoeus и Ethon ), который, как и командная строка curl
, похоже, с радостью принимает пробелы в URL.
Существующий код основывается на строках и содержит ряд махинаций, связанных с удалением дополнительных косые черты, добавление недостающих косых черт и т. д. c. Я пытаюсь заменить это на URI.join()
, но это не удается с bad URI(is not URI?)
на фрагментах с пробелами.
Очевидное решение состоит в использовании (не рекомендуется) URI.escape
, который экранирует пробелы, но оставляет косые черты в одиночестве:
URI.escape('http://example.org/ spaces /<"punc^tu`ation">/non-ascïï ?????/&c.')
# => "http://example.org/%20spaces%20/%3C%22punc%5Etu%60ation%22%3E/non-asc%C3%AF%C3%AF%20%F0%9D%96%88%F0%9D%96%8D%F0%9D%96%86%F0%9D%96%97%F0%9D%96%98/%EF%BC%86%EF%BD%83%EF%BC%8E"
В основном это работает, за исключением случая (3) выше - ранее экранированные компоненты получают двойной экранирование.
s1 = URI.escape(s)
# => "http://example.org/%20spaces%20/%3C%22punc%5Etu%60ation%22%3E/non-asc%C3%AF%C3%AF%20%F0%9D%96%88%F0%9D%96%8D%F0%9D%96%86%F0%9D%96%97%F0%9D%96%98/%EF%BC%86%EF%BD%83%EF%BC%8E"
URI.escape(s)
# => "http://example.org/%2520spaces%2520/%253C%2522punc%255Etu%2560ation%2522%253E/non-asc%25C3%25AF%25C3%25AF%2520%25F0%259D%2596%2588%25F0%259D%2596%258D%25F0%259D%2596%2586%25F0%259D%2596%2597%25F0%259D%2596%2598/%25EF%25BC%2586%25EF%25BD%2583%25EF%25BC%258E"
Рекомендуемые альтернативы URI.escape
, например, CGI.escape
и ERB::Util.url_encode
, не подходят, поскольку они борются с косой чертой (среди других проблем):
CGI.escape(s)
# => "http%3A%2F%2Fexample.org%2F+spaces+%2F%3C%22punc%5Etu%60ation%22%3E%2Fnon-asc%C3%AF%C3%AF+%F0%9D%96%88%F0%9D%96%8D%F0%9D%96%86%F0%9D%96%97%F0%9D%96%98%2F%EF%BC%86%EF%BD%83%EF%BC%8E"
ERB::Util.url_encode(s)
# => "http%3A%2F%2Fexample.org%2F%20spaces%20%2F%3C%22punc%5Etu%60ation%22%3E%2Fnon-asc%C3%AF%C3%AF%20%F0%9D%96%88%F0%9D%96%8D%F0%9D%96%86%F0%9D%96%97%F0%9D%96%98%2F%EF%BC%86%EF%BD%83%EF%BC%8E"
Существует ли чистый, готовый способ сохранить существующие косые черты, побеги и др. c. и избегать только недопустимых символов в строке URI?
Пока что лучшее, что я смог придумать, это что-то вроде:
include URI::RFC2396_Parser::PATTERN
INVALID = Regexp.new("[^%#{RESERVED}#{UNRESERVED}]")
def escape_invalid(str)
parser = URI::RFC2396_Parser.new
parser.escape(str, INVALID)
end
Это кажется на работу:
s2 = escape_invalid(s)
# => "http://example.org/%20spaces%20/%3C%22punc%5Etu%60ation%22%3E/non-asc%C3%AF%C3%AF%20%F0%9D%96%88%F0%9D%96%8D%F0%9D%96%86%F0%9D%96%97%F0%9D%96%98/%EF%BC%86%EF%BD%83%EF%BC%8E"
s2 == escape_invalid(s2)
# => true
, но я не уверен в конкатенации регулярных выражений (даже если это так URI::RFC2396_Parser
работает внутренне), и я знаю, что она не обрабатывает все случаи (например, %
, который не является частью действительного шестнадцатеричного побега, вероятно, должен быть экранирован). Я бы предпочел найти стандартное решение для библиотеки.