所以我有一个奇怪的问题。我在 S3 上有文件,我想使用正则表达式将单词与文件名进行匹配。正则表达式应该清楚地匹配,但它没有:
irb(main):048:0> p.original_filename
=> "Küche.png"
irb(main):049:0> "Küche.png"
=> "Küche.png"
irb(main):013:0> reg = /(\A|\W|\d|_)#{Regexp.quote("Küche")}(\W|\z|\d|_)/i
=> /(\A|\W|\d|_)Küche(\W|\z|\d|_)/i
irb(main):014:0> reg.match?("Küche.png")
=> true
irb(main):015:0> reg.match?(p.original_filename)
=> false
irb(main):050:0> p.original_filename == "Küche.png"
=> false
所以我进一步检查并假设存在编码问题:
irb(main):017:0> p.original_filename.encoding
=> #<Encoding:UTF-8>
irb(main):018:0> "Küche.png".encoding
=> #<Encoding:UTF-8>
这很奇怪。但是让我们看看表示背后的字符和字节是什么:
irb(main):025:0> "Küche.png".chars
=> ["K", "ü", "c", "h", "e", ".", "p", "n", "g"]
irb(main):026:0> p.original_filename.chars
=> ["K", "u", "̈", "c", "h", "e", ".", "p", "n", "g"]
irb(main):032:0> p.original_filename.bytes
=> [75, 117, 204, 136, 99, 104, 101, 46, 112, 110, 103]
irb(main):033:0> "Küche.png".bytes
=> [75, 195, 188, 99, 104, 101, 46, 112, 110, 103]
那么问题来了。我的问题:如何规范化文件名,使其与正则表达式匹配 /(\A|\W|\d|_)#{Regexp.quote("Küche")}(\W|\z|\d|_)/i
?我尝试了 force_encoding
和 encode
但没有成功,因为字节不同。
注意:不能只使用 ASCII 字符作为文件名。这必须与元音一起使用。
最佳答案
在 Unicode 中,某些字符可以表示为基本字符和组合字符:
"\u0075\u0308" # LATIN SMALL LETTER U (U+0075) + COMBINING DIAERESIS (U+0308)
#=> "ü"
或作为单个预组合字符:
"\u00fc" # LATIN SMALL LETTER U WITH DIAERESIS (U+00FC)
#=> "ü"
如果您在键盘上键入字符,它通常会生成后者。
将给定字符串转换为这些表示之一的过程称为规范化。
在 Ruby 中,有 String#unicode_normalize
默认为后一种格式:
a = "\u0075\u0308"
b = "\u00fc"
a.codepoints #=> [117, 776]
b.codepoints #=> [252]
a.unicode_normalize.codepoints #=> [252]
应用于您的示例,您将使用:
reg.match?(p.original_filename.unicode_normalize)
关于ruby-on-rails - 当正则表达式具有不同的字节表示时如何匹配元音变音符 (äöü)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59308479/