Ruby, вызывающий скрипт Python, вызывает ошибку кодирования с немецкими символами - PullRequest
0 голосов
/ 02 июля 2018

Приложение Ruby on rails запускает скрипт Python для получения лемм немецкого слова. Сценарии Python завершаются со следующей ошибкой:

File "/PATHTOSCRIPT/script.py", line 15, in <module>
    for l in sys.stdin:
  File "/PATHTOPYTHON/python3.4/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

Ruby on Rails:

require 'open3'    
@in, @out, stderr = Open3.popen3("/PATHTOSCRIPT/script.py") if ['de'].include? lang

a = "übervölkerung"
@in.write "#{a}\n"
logger.info(@treetagger_out.read.nil?)
logger.info(stderr.read)

Python:

import sys
import os

sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', buffering=1)
for l in sys.stdin:
    l = l.strip()

Я обнаружил, что в Ruby и Python существует разное количество символов:

Ruby:

2.2.3 :006 > a="übervölkerung"
=> "übervölkerung" 
2.2.3 :007 > print a.bytes
[195, 188, 98, 101, 114, 118, 195, 182, 108, 107, 101, 114, 117, 110, 103] => nil 

Python:

>>> a="übervölkerung"
>>> print(list(map(ord, a)))
[252, 98, 101, 114, 118, 246, 108, 107, 101, 114, 117, 110, 103]

1 Ответ

0 голосов
/ 03 июля 2018

Входные данные для вашего скрипта Python, по-видимому, представляют собой текст в кодировке UTF-8. Если вы закодируете свою тестовую строку «übervölkerung» с помощью UTF-8, то первый байт будет C3, который находится в трассировке в начале вашего сообщения.

Это означает, что вам нужно читать STDIN с текстовым потоком, который декодирует UTF-8, а не ASCII. У вас уже есть строка, которая создает оболочку вокруг sys.stdin:

sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', buffering=1)

Это заменяет средство чтения текстового потока по умолчанию (экземпляр io.TextIOWrapper) новым. Но вы не указываете входную кодировку, поэтому используется кодировка по умолчанию, которая определяется средой (на основе переменных среды, специфичных для ОС). В вашем случае кодировка, по-видимому, по умолчанию ASCII, а это не то, что вам нужно. Вам нужен UTF-8, поэтому напишите:

sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', encoding='UTF-8')

(Конечно, вы можете оставить параметр buffering=1 там, если считаете, что он вам нужен.) Кроме того, os.fdopen - это просто более ограниченная версия встроенной функции open. Так что вы можете просто использовать его, ничего не теряя:

sys.stdin = open(sys.stdin.fileno(), 'r', encoding='UTF-8')

Кстати, разница в количестве символов, которую вы видите между Ruby и Python, связана с тем, что вы смотрите на разные вещи. В коде Ruby вы смотрите на байты текста в кодировке UTF-8, а в Python вы смотрите на кодовые точки (Unicode). Во втором случае каждое число соответствует одному символу, а несколько чисел соответствуют символу в первом случае. Чтобы увидеть значения байтов в Python, выполните:

>>> a = "übervölkerung"
>>> list(a.encode('utf8'))
[195, 188, 98, 101, 114, 118, 195, 182, 108, 107, 101, 114, 117, 110, 103]

Я не знаю, как увидеть кодовые точки в Ruby.

...