ruby 1.9,force_encoding,但检查

jro*_*ind 25 ruby character-encoding

我有一个我从某种输入中读过的字符串.

据我所知,它是UTF8.好的:

string.force_encoding("utf8")
Run Code Online (Sandbox Code Playgroud)

但是如果这个字符串中包含的字节实际上不是合法的UTF8,我现在想知道并采取行动.

通常,如果遇到这样的字节,force_encoding("utf8")会提高吗?我相信它不会.

如果我正在做#encode,我可以从方便的选项中选择如何处理源编码(或目标编码)中无效的字符.

但是我没有做#encode,我正在做一个#force_encoding.它没有这样的选择.

它会有意义吗?

string.force_encoding("utf8").encode("utf8")
Run Code Online (Sandbox Code Playgroud)

马上得到一个例外?通常 utf8 utf8的编码没有任何意义.但是,如果存在无效字节,这可能是让它立即提升的方法吗?或者使用:replace选项etc来执行与无效字节不同的操作?

但是,不,似乎也无法做到这一点.

谁知道?

1.9.3-p0 :032 > a = "bad: \xc3\x28 okay".force_encoding("utf-8")
=> "bad: \xC3( okay"
1.9.3-p0 :033 > a.valid_encoding?
=> false
Run Code Online (Sandbox Code Playgroud)

好的,但我如何找到并消除那些坏字节?奇怪的是,这不会引起:

1.9.3-p0 :035 > a.encode("utf-8")
 => "bad: \xC3( okay"
Run Code Online (Sandbox Code Playgroud)

如果我转换为不同的编码,它会!

1.9.3-p0 :039 > a.encode("ISO-8859-1")
Encoding::InvalidByteSequenceError: "\xC3" followed by "(" on UTF-8
Run Code Online (Sandbox Code Playgroud)

或者,如果我告诉它,它会用"?"代替它.=>

1.9.3-p0 :040 > a.encode("ISO-8859-1", :invalid => :replace)
=> "bad: ?( okay"
Run Code Online (Sandbox Code Playgroud)

因此,当转换为不同的编码时,ruby有智能知道utf-8中的坏字节,并用其他东西替换em.但我不想转换为不同的编码,我想保留utf8 - 但如果那里有一个无效字节,我可能想要提高,或者我可能想用替换字符替换无效字节.

是不是有办法让红宝石这样做?

更新我相信这最终已经添加到2.1中的ruby,在2.1预览版本中使用String#scrub来执行此操作.所以寻找它!

jro*_*ind 16

(更新:请参阅https://github.com/jrochkind/scrub_rb)

所以我编写了一个我需要的解决方案:https://github.com/jrochkind/ensure_valid_encoding/blob/master/lib/ensure_valid_encoding.rb

但是最近才知道这实际上已经内置到stdlib中,你只需要在某种程度上反直觉地将'binary'作为"源代码编码":

a = "bad: \xc3\x28 okay".force_encoding("utf-8")
a.encode("utf-8", "binary", :undef => :replace)
=> "bad: ?( okay"
Run Code Online (Sandbox Code Playgroud)

是的,这正是我想要的.事实证明这个IS内置于1.9 stdlib,它只是没有文档,很少有人知道它(或者很少有人说英语知道它?).虽然我看到这些论点在某个地方的博客上以这种方式使用,所以其他人都知道它!


jro*_*ind 6

在ruby 2.1中,stdlib最终支持这个scrub.

http://ruby-doc.org/core-2.1.0/String.html#method-i-scrub