Имеется скрипт, написанный на Cython, который принимает на вход массив C++ строк, анализирует их с помощью pymorphy2 и обрабатывает результаты анализа. В процессе сборки данный скрипт транслируется в исходный код на C++ с помощью следующей команды:
cython ${SCRIPT_FILENAME} -o "morph-analyzer.cpp" -2
В данном скрипте определена функция, в которой осуществляется взаимодействие с pymorphy2:
cdef analyzeToken(const UnicodeString tok, vector[pair[UnicodeString, vector[shared_ptr[AnalysisResult]]]] &analysis_results):
cdef vector[shared_ptr[AnalysisResult]] res_for_tok
cdef shared_ptr[AnalysisResult] analysis_res
cdef string utf8_str
tok.toUTF8String(utf8_str)
morph_results = morph.parse((utf8_str.c_str()).decode('UTF-8'))
cdef unsigned propMask
for morph_result in morph_results:
analysis_res = make_shared[AnalysisResult]()
if morph_result.score > 0.1:
deref(analysis_res).normalForm = UnicodeString(morph_result.normal_form.encode('UTF-8'))
propMask = 0
if morph_result.tag.POS is not None:
deref(analysis_res).partOfSpeech = UnicodeString(morph_result.tag.POS.encode('UTF-8'))
if 'Name' in morph_result.tag:
propMask |= FIRST_NAME
if 'Patr' in morph_result.tag:
propMask |= PATR
if 'Surn' in morph_result.tag:
propMask |= SECOND_NAME
if 'Init' in morph_result.tag:
propMask |= INIT
if 'Geox' in morph_result.tag:
propMask |= GEOX
deref(analysis_res).nameCharMask = propMask
else:
deref(analysis_res).normalForm = tok
res_for_tok.push_back(analysis_res)
analysis_results.push_back(pair[UnicodeString, vector[shared_ptr[AnalysisResult]]](tok, res_for_tok))
Входная строка, которую нужно проанализировать, подается на вход данной функции как объект класса UnicodeString
(из библиотеки icu4c) под именем tok
. Первым делом производится преобразование переданной строки в объект класса std::string в кодировке utf-8:
cdef string utf8_str
tok.toUTF8String(utf8_str)
Далее, нужно передать эту строку на вход функции pymorphy2.MorphAnalyzer.parse()
, которая принимает родные строки из Python в формате Unicode. Чтобы преобразовать имеющуюся utf-8 строку в нужный формат, вызывается метод bytes.decode('UTF-8')
.
При обработке результатов от pymoprhy2 производится обратное преобразование полученной строки в формат utf-8 с помощью функции encode('UTF-8')
, после чего результат передается на вход конструктору UnicodeString
.
Приведенный выше код корректно работает в системе Linux при использовании Python 2.7.13 and Cython 0.25.2. Однако в Windows при использовании тех же версий Python и Cython строки каким-то образом искажаются, из-за чего pymorphy2 оказывается не в состоянии их обработать. Ниже приведен результат искажения:
Current token: Original word: нижес▒едующем, normal form: ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Должно быть так:
Current token: Original word: нижеследующем, normal form: нижеследующий
Подскажите, пожалуйста, в чем может быть проблема. Хотел бы еще раз подчеркнуть тот факт, что проявляется она только при работе в Windows (версия 8.1).
Update:
Функция analyzeToken
вызывается из другой функции, определенной в том же скрипте:
cdef public analyzeTokens(const vector[UnicodeString] &tokens, map[UnicodeString, vector[shared_ptr[AnalysisResult]]] &analysis_results):
for i in xrange(tokens.size()):
analyzeToken(tokens[i], analysis_results)
которая, в свою очередь, вызывается уже из C++ кода
std::map<UnicodeString, std::vector<std::shared_ptr<AnalysisResult>>> analysisResults;
analyzeTokens(plainTokens, analysisResults);
где plainTokens
- std::vector<UnicodeString>
. Ключевое слово public
в сигнатуре функции заставляет Cython
создавать заголовочный файл, содержащий ее объявление.
Update2:
Изначально текстовые данные считываются из файла:
static bool readAllTextFromFile(const std::string &filename, UnicodeString &outText) {
std::ifstream ifs(filename);
if (ifs.fail()) {
std::cerr << "Error: failed to open " << filename << std::endl;
return false;
}
std::string text {std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>()};
outText = UnicodeString(text.c_str());
return true;
}
Далее считанные текстовые данные проходят некоторую структурную обработку (разбиваются на массивы строк с помощью регулярных выражений) и подаются на вход функции analyzeTokens
:
std::vector<UnicodeString> plainSentences;
split_unistring(plainText, {"\\?","\\.","\\!"}, plainSentences);
for (auto &plainSentence : plainSentences) {
Logger::getLogger() << plainSentence << std::endl;
std::vector<UnicodeString> plainTokens;
split_unistring(plainSentence, {"\\s","\\;","\\:","\\,"}, plainTokens);
Sentence currentSentence;
std::map<UnicodeString, std::vector<std::shared_ptr<AnalysisResult>>> analysisResults;
analyzeTokens(plainTokens, analysisResults);
...
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Иногда при коннекте вылетает исключение
Добрый день, есть таблица в tabeWidget из её строки пытаюсь получить копию во вторую tabeWidget_2 данной конструкцией
Всем привет, надо мне сменить фон рабочего стола, юзаю функцию SystemParametersInfo() "Windowsh" подключил, путь прописал, по нажатию кнопки должна поставиться...
Дали на сессии задание, написать программу в которую вводишь 2 слова, и после этого он выделяет первое слово во втором, пример (сам-САМолёт)...