Ruby - 如何编码URL而不重新编码已编码的字符

时间:2016-06-02 12:36:14

标签: ruby-on-rails ruby

我有一个简单的问题:用户可以通过我网站上的表单中的特定输入发布网址。 我想对发布的网址进行编码,因为有时用户会发送包含奇怪和/或非ascii字符的网址(例如éàç...)。例如:https://www.example.com/url-déjà-vu

所以我尝试使用URI.escape('https://www.example.com/url-déjà-vu')确实有效,但如果您有以下网址:URI.escape('https://somesite.com/page?stuff=stuff&%20'),您会得到: => "https://somesite.com/page?stuff=stuff&%2520"

%字符已编码,不应该是%20已经是编码字符。然后我想我能做到这一点:

URI.escape(URI.decode('https://somesite.com/page?stuff=stuff&%20'))
=> "https://somesite.com/page?stuff=stuff&%20"

但如果您的网址中包含“/”编码,则会出现问题,例如:

URI.escape(URI.decode('http://example.com/a%2fb'))
=> "http://example.com/a/b"

“/”应保持编码状态。

所以...把它们放在一起:我想对用户发布的网址进行编码,但是已经编码的字符在ruby中保持不变。知道如何在不头疼的情况下做到这一点吗?

谢谢:)

1 个答案:

答案 0 :(得分:5)

我想不出一种方法可以做到这一点,而不是一点点kludge。所以我提出了一点点kludge。

URI.escape似乎在所有情况下都可以按照您的方式工作,除非字符已经编码。考虑到这一点,我们可以获取URI.encode的结果,并使用String#gsub仅对这些字符进行“解码”。

以下正则表达式查找%25(编码%),后跟两个十六进制数字,例如%252f返回%2f

require "uri"

DOUBLE_ESCAPED_EXPR = /%25([0-9a-f]{2})/i

def escape_uri(uri)
  URI.encode(uri).gsub(DOUBLE_ESCAPED_EXPR, '%\1')
end

puts escape_uri("https://www.example.com/url-déjà-vu")
# => https://www.example.com/url-d%C3%A9j%C3%A0-vu

puts escape_uri("https://somesite.com/page?stuff=stuff&%20")
# => https://somesite.com/page?stuff=stuff&%20

puts escape_uri("http://example.com/a%2fb")
# => http://example.com/a%2fb

我不保证这是万无一失的,但希望它有所帮助。