У меня есть строка, которую я прочитал из какого-то ввода.
Насколько мне известно, это кодировка 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. Так что ищите это!