2015-05-16 2 views
4

В настоящее время я пытаюсь написать скрипт, который выполняет итерацию по входному файлу и проверяет данные на веб-сайте. Если он находит новые данные, он распечатывает терминал, который он передает, если он не говорит мне, что он терпит неудачу. И наоборот для удаленных данных. Он работал нормально до тех пор, пока входной файл, который я получил, не содержит символ «™». Затем, когда рубин приходит в эту линию, он выплюнул ошибку:Ruby несовместимые кодировки символов

PDAPWeb.rb:73:in `include?': incompatible character encodings: UTF-8 and IBM437 (Encoding::CompatibilityError)

Нарушитель линия простая проверка, чтобы увидеть, если текст на странице существует.

if browser.text.include? (program_name) 

Где переменная program_name - анализируемая часть информации из входного файла. В этом случае имя_программы содержит символ «TM», упомянутый ранее.

После некоторого исследования я обнаружил, что добавление строки # encoding: utf-8 в начало моего скрипта могло бы помочь, но до сих пор не оказалось полезным.

Я добавил это в свою переменную program_name, чтобы узнать, поможет ли она (и это позволило моему сценарию работать без ошибок), но теперь он неправильно находит символ TM, когда он должен быть.

program_name = record[2].gsub("\n", '').force_encoding("utf-8").encode("IBM437", replace: nil) 

Это казалось преобразовать характер ТМ к этому: Γäó

Я подумал, что я имел IBM437 и UTF-8 частей вспять, поэтому я попытался противоположный

program_name = record[2].gsub("\n", '').force_encoding("IBM437").encode("utf-8", replace: nil) 

и теперь я получение этой ошибки при попытке запуска сценария

PDAPWeb.rb:48:in `encode': U+2122 from UTF-8 to IBM437 (Encoding::UndefinedConve rsionError)

Я использую ruby ​​1.9.3p392 (2013-02-22)), и я не уверен, что я должен обновиться, поскольку это стандартная версия, установленная в моей компании.

Является ли моя кодировка неправильной и заставляет ее преобразовывать символ ТМ с ошибками?

+0

Есть причина вы кодируете 'IBM437'? –

+0

Я не был уверен, что у меня был порядок кодирования, я просто пошел с тем, что он сказал в ошибке, изначально (до того, как я добавил какую-либо кодировку) –

+0

«Я подумал, что, возможно, у меня были части IBM437 и utf-8, поэтому я попробовал обратное и теперь получаю эту ошибку при попытке запустить скрипт «Можете ли вы показать этот код. Что-то не имеет смысла. –

ответ

6

Вот как он выглядит. Ваш входной файл содержит символ , и он находится в кодировке UTF-8. Однако, когда вы его читаете, поскольку вы не указываете кодировку, Ruby предполагает, что она находится в кодировке по умолчанию для системы IBM437 (вы должны быть в Windows).

Это в основном так же, как это:

>> input = "™" 
=> "™" 
>> input.encoding 
=> #<Encoding:UTF-8> 
>> input.force_encoding 'ibm437' 
=> "\xE2\x84\xA2" 

Обратите внимание, что force_encoding не изменяет фактическую строку, только ярлык, связанный с ним. Это тот же результат, что и в вашем случае, только вы приходите сюда по другому маршруту (читая файл).

Веб-страница также имеет символ, а также кодируется как UTF-8, но в этом случае Рубин имеет кодировку правильно (Watir, вероятно, использует заголовки со страницы):

>> web_page = '™' 
=> "™" 
>> web_page.encoding 
=> #<Encoding:UTF-8> 

сейчас при попытке сравнить эти две строки вы получите ошибку совместимости, потому что они имеют разные кодировки:

>> web_page.include? input 
Encoding::CompatibilityError: incompatible character encodings: UTF-8 and IBM437 
    from (irb):11:in `include?' 
    from (irb):11 
    from /Users/matt/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>' 

Если какой-либо из двух строк содержали только ASCII символы (т.е.меньше кодов, чем 128), тогда это сравнение сработало бы. Оба UTF-8 и IBM437 являются суперсетами ASCII и являются только несовместимыми, если оба они содержат символы вне диапазона ASCII. Вот почему вы только начали видеть это поведение, когда входной файл имел .

Исправление состоит в том, чтобы сообщить Ruby, что такое фактическое кодирование входного файла. Вы можете сделать это с уже загруженной строки:

>> input.force_encoding 'utf-8' 
=> "™" 

Вы также можете сделать это, когда reading the file, например, (Есть несколько способов чтения файлов, все они должны позволить вам явно указать кодировку):

input = File.read("input_file.txt", :encoding => "utf-8") 
# now input will be in the correct encoding 

Примечание в обоих из них строка не изменяется, она по-прежнему содержит те же байты, но Ruby теперь знает правильную кодировку.

Теперь сравнение должно работать нормально:

>> web_page.include? input 
=> true 

Там нет необходимости encode строки. Вот что произойдет, если вы это сделаете. Во-первых, если вы исправить кодировку UTF-8 затем закодировать IBM437:

>> input.force_encoding("utf-8").encode("IBM437", replace: nil) 
Encoding::UndefinedConversionError: U+2122 from UTF-8 to IBM437 
    from (irb):16:in `encode' 
    from (irb):16 
    from /Users/matt/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>' 

IBM437 не включает характер, так что вы не можете кодировать строку, содержащую его в эту кодировку без потери данных. По умолчанию Ruby вызывает исключение, когда это происходит. Вы можете заставить кодировку с помощью опции :undef, но символ теряется:

>> input.force_encoding("utf-8").encode("IBM437", :undef => :replace) 
=> "?" 

Если вы идете в другую сторону, сначала с помощью force_encoding в IBM437 затем кодировании в UTF-8, вы получить строку Γäó:

>> input.force_encoding("IBM437").encode("utf-8", replace: nil) 
=> "Γäó" 

Строка уже находится в кодировке IBM437 до Ruby, поэтому force_encoding ничего не делает. Представление UTF-8 - это три байта 0xe2 0x84 0xa2, а при интерпретации IBM437 эти байты соответствуют трем символам, которые здесь отображаются, которые затем преобразуются в их представления UTF-8.

(Эти два результата являются наоборот от того, что вы описали в этом вопросе, поэтому мой комментарий выше. Я предполагаю, что это просто ошибка копирования и вставки.)

+0

Одна вещь, которую я обнаружил, заключается в том, что когда я захватываю строку в браузере, используя watir, используя простую строку browser.p (: class => 'target_class'). text возвращает «Some text \ u2122 some more text», поэтому мне действительно нужно преобразовать один из них, чтобы они соответствовали друг другу –

+0

@ToddJ. Я так не думаю. Ruby печатает '\ u2122', потому что терминал не поддерживает печать фактического символа' '' (или Ruby не думает, что он может). '\ u2122'_is_' ™ '. – matt

+0

Вы были правы! Я смог сделать тест, и все работает так, как ожидалось. –

Смежные вопросы