使用Ruby(使用Addressable Gem)从标准化的URI中显示国际化域名(IDN)。

5
在我的Ruby应用程序中,我需要处理来自用户输入的URI(实际上是IRI)。
str = "http://उदाहरण.परीक्षा/मुख्य_पृष्ठ"

我使用Addressable对它们进行规范化,并仅存储规范化的形式:

normalized = Addressable::URI.parse(str).normalize
normalized.to_s
#=> http://xn--p1b6ci4b4b3a.xn--11b5bs3a9aj6g/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A5%8D%E0%A4%AF_%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0

这很好用,但显然不适合展示给最终用户。

因此,我想将此URI转换回其原始形式(非punycode,非百分号编码路径)。

Addressable有display_uri,但它只转换主机部分:

nicer = normalized.display_uri.to_s
#=> http://उदाहरण.परीक्षा/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A5%8D%E0%A4%AF_%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0

看起来这个可以工作:

display_s = Addressable::URI.parse(str).display_uri.to_s
pretty = Addressable::URI.unencode(display_s.force_encoding("ASCII-8BIT"))

然而,该代码看起来有误(我不应该需要使用force_encoding),并且我并不确定它是否正确。
  • 将整个URI转换为对终端用户可用的内容("http://उदाहरण.परीक्षा/मुख्य_पृष्ठ")的好方法是什么?

  • 规范化存储URI是一个好主意吗?或者这样做可能会有我没有意识到的后果?

代码:https://gist.github.com/levinalex/6115764

简而言之

我如何将以下内容转换:

"http://xn--p1b6ci4b4b3a.xn--11b5bs3a9aj6g/" +
"%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A5%8D%E0%A4" +
"%AF_%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0"

转换为:

"http://उदाहरण.परीक्षा/मुख्य_पृष्ठ"

首先,使用Addressable加1。如果您的数据库可以正常接受它,则我不认为存储规范化的URI有很多优势。如果规范化,它会更长,不明显是什么,而且搜索起来更困难。 - the Tin Man
对数据进行了归一化以保持一致性并检测重复。起初看起来很简单,现在我不太确定了。 - levinalex
重复检测可以通过在该字段的索引上使用“unique”设置,由数据库自动处理。您的代码不应尝试跟踪它,而是应在DBM拒绝插入/更新时响应“找到重复键”类型错误。您可能需要规范化以解决具有指向相同字符的多个代码点的字符,因为这种差异会欺骗索引。或者,如果这最终导致将URL更改为解析不同的内容,则可能不需要进行规范化;这就是puny-code的优势所在。这是一个艰难的抉择。 - the Tin Man
1
如果一切都被规范化了,那么只有在这种情况下数据库的唯一性才会有任何好处。因此,如果需要检测重复项,则在将字段存储到数据库之前进行规范化是100%正确的选择。 - Bob Aman
1个回答

0

您不需要任何强制(重新)编码来恢复原始URI。只需:

normalised_s = "http://xn--p1b6ci4b4b3a.xn--11b5bs3a9aj6g/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A5%8D%E0%A4%AF_%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0"        
Addressable::URI.unencode(Addressable::URI.parse(normalised_s).display_uri)

=> "http://उदाहरण.परीक्षा/मुख्य_पृष्ठ"

重申一下Bob在评论中的话,规范化绝对是确保存储唯一性的好方法。


我可以确认这个在Addressable 2.3.6中可行。 - levinalex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接