Webフォームから写真やキャプションを選択するRuby CGI(Railsではありません)。これらの非ASCII文字をうまく処理しません、非ASCII文字を取り除くことができる迅速なRuby文字列操作ルーチンはありますか?
Ruby 1.9の時点で文字列エンコーディング間で変換する公式の方法は、 String#encode を使用することです。
非ASCII文字を単純に削除するには、次のようにします。
_some_ascii = "abc"
some_unicode = "áëëçüñżλφθΩ????????"
more_ascii = "123ABC"
invalid_byte = "\255"
non_ascii_string = [some_ascii, some_unicode, more_ascii, invalid_byte].join
# See String#encode documentation
encoding_options = {
:invalid => :replace, # Replace invalid byte sequences
:undef => :replace, # Replace anything not defined in ASCII
:replace => '', # Use a blank for those replacements
:universal_newline => true # Always break lines with \n
}
ascii = non_ascii_string.encode(Encoding.find('ASCII'), encoding_options)
puts ascii.inspect
# => "abce123ABC"
_
結果の最初の5文字は「abce1」であることに注意してください。「á」は破棄され、「ë」は破棄されますが、別の「ë」は「e」に変換されたようです。
これは、同じ文字をUnicodeで表現する方法が複数ある場合があるためです。 「á」は単一のUnicodeコードポイントです。最初の「ë」も同様です。この変換中にRubyがこれらを検出すると、それらを破棄します。
しかし、2番目の "ë"は2つのコードポイントです。ASCII文字列に続くように、普通の "e"に続いて "結合発音区別記号"( this one )、これは「前の文字にウムラウトを付ける」ことを意味します。Unicode文字列では、これらは単一の「書記素」または可視文字として解釈されます。これを変換するとき、Ruby =はプレーンASCII "e"を保持し、結合マークを破棄します。
特定の置換値を提供する場合は、次の操作を実行できます。
_REPLACEMENTS = {
'á' => "a",
'ë' => 'e',
}
encoding_options = {
:invalid => :replace, # Replace invalid byte sequences
:replace => "", # Use a blank for those replacements
:universal_newline => true, # Always break lines with \n
# For any character that isn't defined in ASCII, run this
# code to find out how to replace it
:fallback => lambda { |char|
# If no replacement is specified, use an empty string
REPLACEMENTS.fetch(char, "")
},
}
ascii = non_ascii_string.encode(Encoding.find('ASCII'), encoding_options)
puts ascii.inspect
#=> "abcaee123ABC"
_
_:universal_newline
_オプションの問題を報告している人もいます。私はこれを断続的に見ましたが、原因を突き止めることができませんでした。
それが起こると、Encoding::ConverterNotFoundError: code converter not found (universal_newline)
が表示されます。ただし、RVMを更新した後、次のRubyバージョンで問題なく上記のスクリプトを実行しました。
これを考えると、それは非推奨の機能やRubyのバグでさえないようです。誰かが原因を知っている場合は、コメントしてください。
class String
def remove_non_ascii(replacement="")
self.gsub(/[\u0080-\u00ff]/, replacement)
end
end
Iconvを使用した私の提案は次のとおりです。
class String
def remove_non_ascii
require 'iconv'
Iconv.conv('ASCII//IGNORE', 'UTF8', self)
end
end
class String
def strip_control_characters
self.chars.reject { |char| char.ascii_only? and (char.ord < 32 or char.ord == 127) }.join
end
end
@masakielasticの助けを借りて、個人的な目的で#charsメソッドを使用してこの問題を解決しました。
トリックは、各文字を独自の個別ブロックに分解することです= Rubyは失敗する可能性があります。
Rubyは、バイナリコードなどに直面したときに失敗する必要があります。Rubyが先に進み失敗することを許可しない場合このことに関しては難しい道です。String#charsメソッドを使用して、指定された文字列を文字の配列に分割します。次に、そのコードをサニタイズメソッドに渡します。コイン))文字列内。
したがって、「ダーティ」文字列が与えられた場合、File#read
写真。 (私の場合)
dirty = File.open(filepath).read
clean_chars = dirty.chars.select do |c|
begin
num_or_letter?(c)
rescue ArgumentError
next
end
end
clean = clean_chars.join("")
def num_or_letter?(char)
if char =~ /[a-zA-Z0-9]/
true
elsif char =~ Regexp.union(" ", ".", "?", "-", "+", "/", ",", "(", ")")
true
end
end
いいえ、基本的な文字以外のすべての文字を削除することもできます(上記をお勧めします)。最良の解決策は、これらの名前を適切に処理することです(現在のほとんどのファイルシステムにはUnicode名に関する問題がないため)。ユーザーが合字を貼り付けると、地獄でそれらを取り戻したいと思うでしょう。ファイルシステムが問題の場合は、ファイルシステムを抽象化し、ファイル名をmd5に設定します(これにより、エントリが多すぎないため、非常に迅速にスキャンするバケットに簡単に断片をアップロードできます)。
Quick GSは この議論 を明らかにしました。これは次の方法を示唆しています:
class String
def remove_nonascii(replacement)
n=self.split("")
self.slice!(0..self.size)
n.each { |b|
if b[0].to_i< 33 || b[0].to_i>127 then
self.concat(replacement)
else
self.concat(b)
end
}
self.to_s
end
end