ruby ​​1.9, force_encoding, но проверьте

У меня есть строка, которую я прочитал из какого-то ввода.

Насколько мне известно, это кодировка UTF8. Хорошо:

string.force_encoding("utf8")

Но если в этой строке есть байты, которые на самом деле не являются законными UTF8, я хочу узнать об этом сейчас и принять меры.

Будет ли вызываться force_encoding("utf8") при обнаружении таких байтов? Я верю, что не будет.

Если бы я выполнял #encode, я мог бы выбрать из удобных опций, что делать с символами, которые недопустимы в исходной кодировке (или кодировке назначения).

Но я не делаю #encode, я делаю #force_encoding. У него нет таких опций.

Имеет ли смысл

string.force_encoding("utf8").encode("utf8")

получить исключение сразу? Обычно кодирование из utf8 в utf8 не имеет никакого смысла.Но, может быть, это способ заставить его сразу подняться, если есть недопустимые байты? Или использовать опцию :replaceи т. д., чтобы сделать что-то другое с недопустимыми байтами?

Но нет, похоже, это тоже не работает.

Кто-нибудь знает?

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

Хорошо, но как мне найти и удалить эти плохие байты? Как ни странно, это НЕ вызывает:

1.9.3-p0 :035 > a.encode("utf-8")
 => "bad: \xC3( okay"

Если бы я конвертировал в другую кодировку, это было бы!

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

Или, если я скажу, он заменит его на "?" =>

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

Итак, у ruby ​​достаточно ума, чтобы знать, что такое плохие байты в utf-8, и заменять их чем-то другим — при преобразовании в другую кодировку. Но я не хочупреобразовывать в другую кодировку, я хочу остаться в utf8 -- но я мог бы захотеть повысить, если там есть недопустимый байт, или я мог бы заменить недопустимые байты заменой символы.

Нет ли способа заставить руби сделать это?

updateЯ считаю, что это, наконец, было добавлено в ruby ​​​​в версии 2.1, и для этого в предварительной версии 2.1 присутствует String#scrub. Так что ищите это!

25
задан jrochkind 9 October 2013 в 22:39
поделиться