Страницы

Поиск по вопросам

Показаны сообщения с ярлыком unicode. Показать все сообщения
Показаны сообщения с ярлыком unicode. Показать все сообщения

понедельник, 13 апреля 2020 г.

Unicode при записи в файл

#windows #unicode #console #visual_studio #cpp

                    
Мне нужно создать консольное приложение, которое 

Считывало бы введённые пользователем символы: как англоязычные, так и русскоязычные.
Выводила бы эти символы на экран в консоль.
Записывала бы эти символы в файл.

С первым и вторым пунктом, как убрать кракозябры, я разобрался следующим образом:


Подключил #include 


Весь вывод стал пропускать через функцию ToRus т.е. cout<< ToRus(L"Почему всё так
сложно!")


Вот сама функция:
char *ToRus(wchar_t *str) {   
static char s[1024];   
CharToOem(LPCWSTR(str), s);    
return s; }

Но осталась проблема 3-м пунктом - с выводом в файл. В файл по-прежнему выводятся
кракозябры. Подскажите, пожалуйста, как решить проблему, как сделать так, чтобы в файл
нормально выводилась? Может вообще, как-то по-другому нужно было делать?    


Ответы

Ответ 1



Нашёл! Вот вам статья: http://www.codeproject.com/Articles/4563/Upgrading-an-STL-based-application-to-use-Unicode. (Не смотрите часть с tstream/TCHAR, вам нужно просто wstream.) Или то же здесь: http://forums.codeguru.com/showthread.php?457106-Unicode-text-file&p=1741409#post1741409. Проблема в том, что обыкновенный wfstream принимает Unicode-строки, а вот пишет их как не-Unicode. Но его можно заставить. Вот вам вкратце описание, как. Первый шаг: создаёте «пустой» конвертер. В обычном случае wchar_t* конвертируется с потерями в обычные символы, но нам надо эту конвертацию отключить. Код конвертера: #include #include #include #include #include typedef std::codecvt null_wcodecvt_base; class null_wcodecvt : public null_wcodecvt_base { public: explicit null_wcodecvt(size_t refs = 0) : null_wcodecvt_base(refs) {} protected: virtual result do_out(mbstate_t&, const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next, char* to, char* to_end, char*& to_next) const { size_t len = (from_end - from) * sizeof(wchar_t); memcpy(to, from, len); from_next = from_end; to_next = to + len; return ok; } virtual result do_in(mbstate_t&, const char* from, const char* from_end, const char*& from_next, wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const { size_t len = (from_end - from); memcpy(to, from, len); from_next = from_end; to_next = to + (len / sizeof(wchar_t)); return ok; } virtual result do_unshift(mbstate_t&, char* to, char*, char*& to_next) const { to_next = to; return noconv; } virtual int do_length(mbstate_t&, const char* from, const char* end, size_t max) const { return (int)((max < (size_t)(end - from)) ? max : (end - from)); } virtual bool do_always_noconv() const throw() { return true; } virtual int do_encoding() const throw() { return sizeof(wchar_t); } virtual int do_max_length() const throw() { return sizeof(wchar_t); } }; Теперь, надо ещё переопределить endl. std::wostream& wendl(std::wostream& out) { out.put(L'\r'); out.put(L'\n'); out.flush(); return out; } А вот и пример использования. Не забудьте про BOM (такая штука в начале файла, может и не понадобиться, если не под Windows). const wchar_t UTF_BOM = 0xfeff; int main() { // заводим файл std::wfstream file; // инстанциируем пустой конвертер null_wcodecvt wcodec(1); std::locale wloc(std::locale::classic(), &wcodec); // сообщаем файлу, что он должен использовать этот конвертер, // а не стандартный. обязательно делаем это _до_ открытия файла file.imbue(wloc); // открыли файл, обязательно как binary, чтобы никакой самодеятельности // от стандартной библиотеки file.open("data.txt", std::ios::out | std::ios::binary); if (!file) { // если текст русский, надо прогнать через `ToRus` std::cerr << "Failed to open data.txt for writing" << std::endl; return 1; } // записали в начало файла BOM file << UTF_BOM; // записали текст file << L"Я тоже не знаю, почему в C/C++ всё так сложно." << wendl; // закрыли файл file.close(); // фсё! return 0; }

суббота, 11 апреля 2020 г.

Как убрать BOM из файла?

#файлы #unix #unicode

                    
Как консольно (в Unix-like окружении) удалить BOM (byte-order mark, непечатаемый
символ в самом начале файла, являющийся необязательной меткой юникода) из файла?
    


Ответы

Ответ 1



Например, с помощью awk: awk '{if(NR==1)sub(/^\xef\xbb\xbf/, "");print}' < oldfile > newfile

Ответ 2



Если точно знаете, что файл с BOM $ tail -c +4 newfile эффективно копирует все, пропустив первые 3 байта (см. man tail for details)

Ответ 3



С помощью sed: $ sed -e '1s/^\xef\xbb\xbf//' < bomfile > newfile Если заранее известно, что файл содержит BOM, то можно использовать dd: $ dd if=bomfile of=newfile bs=3 skip=1

воскресенье, 8 марта 2020 г.

Обновление ICU на PHP7

#php #ubuntu #unicode


Подскажите, какие есть способы обновить ICU до актуальной версии на PHP7 на Ubuntu 14.04?
Ставил php7 из ppa репозитория ondrej. Пытался обновить ICU через pecl, но для 7
версии этот способ не работает. Получается выход только один - компилировать PHP из
исходников и указывать icu вручную? Подскажите, как это сделать?
    


Ответы

Ответ 1



После долгих поисков я пришел к выводу что проще всего скомпилировать intl из репозитория php. Ниже привожу мой пример для icu5.8.1 который ставится в /opt/icu5c на php-7.0.8. Для других версий нужно изменить пути к файлам соответсвенно. sudo su #Install ICU wget http://download.icu-project.org/files/icu4c/58.1/icu4c-58_1-src.tgz tar zxvf icu4c-58_1-src.tgz cd icu/source ./configure --prefix=/opt/icu5c && make && make install #Install intl.so from php source cd ../.. wget https://github.com/php/php-src/archive/php-7.0.8.tar.gz tar -xvf php-7.0.8.tar.gz cd php-src-php-7.0.8/ext/intl export LD_LIBRARY_PATH=/opt/icu5c/lib phpize ./configure --enable-intl --with-icu-dir=/opt/icu5c make make install #Activate extension (cli and fpm) echo "extension=intl.so" > /etc/php/7.0/mods-available/intl.ini ln -s /etc/php/7.0/mods-available/intl.ini /etc/php/7.0/cli/conf.d/20-intl.ini ln -s /etc/php/7.0/mods-available/intl.ini /etc/php/7.0/fpm/conf.d/20-intl.ini

Ответ 2



Для тех у кого при команде make выдаются ошибки для ICU версии >=59.1, как у комментария @Arkemlar, мне помогли следующие флаги для компилятора make CXXFLAGS="-g -std=c++11" Комментом не смог добавить, из за репутации инфу

понедельник, 24 февраля 2020 г.

Byte при печати вывода внешней команды

#python #windows #python_3x #unicode #subprocess


Для лабораторки использую кусок кода:

import socket, sys, os, subprocess

ipconfig_res = subprocess.Popen("ipconfig", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in ipconfig_res.stdout.readlines():
    print (line)


При запуске в 3.5 выдается список с содержимым типа bytes, преобразовать его в str
не получается. Как получить результат без мусора?  


    


Ответы

Ответ 1



Это не мусор, а байтовое представление строк, их нужно кодировать, чтобы получить человеко-читаемый вид: ipconfig_res = subprocess.Popen("ipconfig", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in ipconfig_res.stdout.readlines(): line = line.strip() if line: print(line.decode('cp866')) Консоль: Настройка протокола IP для Windows Ethernet adapter VPN - VPN Client: Состояние среды. . . . . . . . : Среда передачи недоступна. DNS-суффикс подключения . . . . . : Ethernet adapter Подключение по локальной сети 4: Состояние среды. . . . . . . . : Среда передачи недоступна. ... Еще пример: >>> b'\x8d\xa0\xe1\xe2'.decode('cp866') 'Наст' Исправленный, по советам jfs, код: from subprocess import Popen, PIPE if __name__ == '__main__': ipconfig_res = Popen("ipconfig", universal_newlines=True, stdout=PIPE) for line in ipconfig_res.stdout: print(line, end='')

Ответ 2



subprocess модуль использует байты для обмена данными с дочерним процессом. b'\r\n' это текстовое представление (repr(bytes_object)) двоичных данных, представленных типом bytes в Питоне -- объект, представляющий последовательность двух байт (0x0d, 0x0a) в этом примере. Обычно текстовое представление показывается в интерактивной консоле Питона, где sys.displayhook использует repr(), чтобы показать объекты по умолчанию (полезно для отладки) или если вы пытаетесь напечатать байты, используя текстовый интерфейс (например, print(bytes_object)) -- нужно текст передавать вместо этого. Как получить текст из вывода внешней команды Чтобы получить текст из байт, их необходимо декодировать в Юникод, используя зависящую от команды, её опций и окружения кодировку: text = subprocess.check_output("ipconfig", encoding=encoding) До Python 3.6, Popen() не принимал encoding параметр, поэтому чтобы произвольную кодировку передать, можно явно io.TextIOWrapper() создать. Чтобы построчно вывод прочитать: #!/usr/bin/env python3 import io from subprocess import Popen, PIPE, STDOUT with Popen("ipconfig", stdout=PIPE, stderr=STDOUT, bufsize=1) as process: for line in io.TextIOWrapper(process.stdout, encoding=encoding): # здесь с line можно работать print(line, end='') Если передать universal_newlines=True в Popen(), то TextIOWrapper() используется неявно и соответственно locale.getpreferredencoding(False) кодировка используется, чтобы декодировать байты в текст. Дополнительно, окончания строк нормализируются, например, '\r\n' на входе преобразуется в '\n'. Обычно ipconfig расположен в одном из стандартных путей, просматриваемых Popen() в поиске исполняемого файла и ipconfig не является внутренней командой в cmd.exe, поэтому shell=True не нужно использовать. Как определить кодировку, чтобы вывод команды декодировать Не нужно жёстко прошивать кодировку окружения, в котором исполняется ваш Питон-скрипт. Иначе получатся кракозябы, если вы запустите команду в окружении, которое может использовать другую несовместимую кодировку символов. См.: Возвращаемая строка содержит нечитаемые символы Проблемы с кодировкой Python 2.7 Используемая кодировка для вывода зависит от команды, её опций и текущего окружения, например, Питон 3 использует encoding=locale.getpreferredencoding(False) по умолчанию -- что-нибудь вроде cp1251 на русской Винде. cmd.exe по умолчанию использует OEM code page (см. вывод chcp команды) -- что-нибудь вроде cp866. Если родительский процесс подключён к той же консоле и chcp не был использован для смены кодировки, то можно использовать encoding=os.device_encoding(1), который вызывает GetConsoleOutputCP() на Windows (это значение может отличаться от encoding=ctypes.windll.kernel32.GetOEMCP()). cmd /U использует utf-16 кодировку. Наиболее вероятно, что вывод ipconfig можно декодировать, используя encoding=os.device_encoding(1) or ctypes.windll.kernel32.GetOEMCP() в этом случае (первое не None значение).

воскресенье, 9 февраля 2020 г.

Посимвольный вывод слов

#php #utf_8 #unicode


Здравствуйте!

Есть такая конструкция, которая выведет первую букву переменной $str, которая будет
равна 't':

mb_internal_encoding("UTF-8");
$str = 'test';
print_r($str[0]);   //    выведет 't'


Но почему это не работает с русскими словами?

mb_internal_encoding("UTF-8");
$str = 'тест';
print_r($str[0]);   //    выведет '�', вместо 'т'


Кодировка вроде выставлена, но почему в выводе  знак вопроса?

Подскажите, пожалуйста, как решить?

Спасибо!
    


Ответы

Ответ 1



Всё дело в том, что в кодировке UTF-8 единичный символ может занимать разное количество байт (от 1 до 6 или даже больше). Английские буквы, цифры, некоторые знаки препинания занимают по одному байту, и их представление ничем не отличается, как если бы они были закодированы в ASCII. Для букв русского алфавита, букв европейских языков, которых нет английском (например, немецкая Ö), для арабского алфавита, нужно уже по два байта. Распространённые восточные иероглифы занимают уже по 3 байта каждый. А всеми любимые эмодзи кодируются последовательностями от 4 байтов. Итак, давайте рассмотрим байтовое представление ваших строк. test -> 74 65 73 74 тест -> D1 82 D0 B5 D1 81 D1 82 Слева показано то, как эти буквы видим мы, справа — их побайтовое представление в памяти компьютера, причём значения байтов записаны в 16-ричной системе счисления (чтобы не занять много места). Как видите, русское слово занимает в два раза больше памяти, хотя букв в нём столько же. Кроме того, обратите внимание, каждый байт в его кодированном варианте не меньше 8016. Теперь вернёмся к PHP. Строки в этом языке о кодировках ничего не знают, а просто хранят в себе только байты. И оператор индексирования тоже ничего про кодировки, буквы, символы не знает; он просто, будучи применённым к строке, возвращает байт с указанным номером. Поэтому, когда вы пытаетесь напечатать первый байт (с номером 0), в первом случае выводится байт со значением 7416, который на экране компьютера виден как маленькая латинская буква «t». А во втором случае на вывод подаётся байт со значением D116, представляющий собой огрызок русской буквы «т»; не зная, какой байт идёт дальше, устройство вывода (терминал или веб-обозреватель) просто рисует знак вопроса. Что же делать, как напечатать только первый символ из строки? В качестве решения можно применить функции из расширения php-mbstring. $letter = mb_substr($str, 0, 1); // вернёт первый code point из строки Но учтите, функция mb_substr оперирует понятием code point, а не graphical cluster. Какое же это имеет значение? Стандарт юникода позволяет составлять некоторые буквы из нескольких code points. К примеру, буква «ё» может оказаться комбинацией буквы «е» и умляута.

Ответ 2



Используйте mb_substr: mb_substr($string, $letter, 1, "utf-8"); //$string - строка //$letter - индекс нужной буквы //1 - сколько символов включая нужную нужно вернуть //"utf-8" - кодировка

воскресенье, 2 февраля 2020 г.

Python: 'charmap' codec can't decode byte 0x98

#python #windows #python_3x #console #unicode


Добрый день
Считываю utf8-файл и вывожу в консоль. При попытке вывести букву "И" возникает ошибка:

File "I:\ProgramFile\Anaconda\lib\encodings\cp1251.py", line 15, in decode  
    return codecs.charmap_decode(input,errors,decoding_table)  
UnicodeDecodeError: 'charmap' codec can't decode byte 0x98 in position 1: character
maps to < undefined >


Воспроизводится на вот таком примере:

test_text_1 = "Задача\n"
test_text_2 = "Итератор"

file = open('temp.txt', 'w', encoding='utf-8')
file.write(test_text_1)
file.write(test_text_2)
file.close()

text = open('temp.txt', 'rb')

for byte_code in text:
    print(byte_code.strip())
    test_text = byte_code.decode('cp1251')
    print(test_text.strip())


Первое слово выводится нормально, а на втором - ошибка. Никак не могу найти способ
побороть проблему.

UPD: Видимо я описал проблему слишком широко, исправляюсь:

Как конвертировать "И" из utf-8 в cp1251? Для "А" всё работает, а для "И" - нет.

Код:

byte1 = 'А'.encode('utf-8')
byte2 = 'И'.encode('utf-8')
print(byte1, byte2)
test1 = byte1.decode('cp1251')
print(test1)
test2 = byte2.decode('cp1251')
print(test2)

    


Ответы

Ответ 1



Чтобы напечатать файл, содержащий текст в utf-8 кодировке, в консоль (аналог type filename в cmd.exe) в Питоне: #!/usr/bin/env python3 import shutil import sys with open(filename, encoding='utf-8') as file: shutil.copyfileobj(file, sys.stdout) Если хочется напечатать Юникодные символы, которые непредставимы в chcp кодировке (OEM code page), то см. Как из Python вывести на Windows-консоль строку в Юникоде?

Ответ 2



Если у вас файл записан в кодировке utf-8, то и декодировать нужно из кодировки utf-8: ... for byte in text: print(byte.strip()) text = byte.decode('utf-8') print(text.strip()) Результат: b'\xd0\x97\xd0\xb0\xd0\xb4\xd0\xb0\xd1\x87\xd0\xb0' Задача b'\xd0\x98\xd1\x82\xd0\xb5\xd1\x80\xd0\xb0\xd1\x82\xd0\xbe\xd1\x80' Итератор Когда вы записываете текст в файл в какой-то кодировке, вы фактически превращаете внутреннее представление текста в байты в указанной кодировке. Чтобы правильно декодировать эти байты обратно во внутреннее представление, при декодировании нужно указать ту же кодировку, что и при записи.

среда, 29 января 2020 г.

('%EF%BB%BF' , '%C2%A0') Что это за символы и как их удалить из url?

#php #строки #utf_8 #unicode


Помогите пожалуйста решить.

1) var_dump('%EF%BB%BF'); //string(3) ""

2) var_dump('%C2%A0'); // string(2) " "


Первый вроде пустая строка,как может быть результат var_dum = string(3) "".

Другого объяснения как юникод я не знаю.Походу эти (utf-8) невидимые символы и есть.

Самый простой вариант 

var_dump(explode('%', 'aaa%EF%BB%BF')[0]);


Но насколько правильно поступать таким образом я не уверен

Если это так то надо учесть что может быть этот пробел под другой кодировкой выглядит
иначе и как можно очистить от него строку ?
    


Ответы

Ответ 1



%EF%BB%BF - BOM - Byte Order Mark для Unicode. %C2%A0 - Utf-8 non breaking space В таком формате Вы видите их в URL, в php же они приходят как: %EF%BB%BF => pack("CCC",0xef,0xbb,0xbf) %C2%A0 => pack("CC",0xc2,0xa0) Ну, или проще: urldecode('%C2%A0') Именно так их и нужно проверять. В этом вашем примере в исходной строке все символы печатные: var_dump(explode('%', 'aaa%EF%BB%BF')[0]); Удалить можно так: function removeBOM($str=""){ if(substr($str, 0,3) == pack("CCC",0xef,0xbb,0xbf)) { $str=substr($str, 3); } return $str; } И так: $str = preg_replace('/\xA0/u', '', 'A'.pack("CC",0xc2,0xa0).'B'); Удалить все непечатаемые символы: $str = preg_replace('/[^[:print:]]/', '', $str); Demo var_dump(preg_replace('/\xA0/u', '', urldecode("Word%C2%A0Word"))); // WordWord var_dump(preg_replace('/[^[:print:]]/', '', urldecode("%EF%BB%BFWord%C2%A0Word"))); // WordWord

Ответ 2



Перевод этого ответа 7-битный ASCII? Если вы вдруг оказались в 1963 году, и всего лишь хотите использовать печатные символы 7-битного ASCII, то нужно всего лишь удалить все символы в диапазоне кодов 0-31 и 127-255: $string = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $string); 8-битный расширенный ASCII? В 1963 вам не понравилось и вы переместились в восьмидесятые и столкнулись с 8-битным ASCII, в котором символы 128-255 являются обычными, отображаемыми, символами. Тогда вам нужно лишь слегка скорректировать строку замены и удалять символы 0-31 и 127: $string = preg_replace('/[\x00-\x1F\x7F]/', '', $string); UTF-8? Добро пожаловать в 21 век! Если ваша строка является строкой UTF-8, то вам придется использовать модификатор \u: $string = preg_replace('/[\x00-\x1F\x7F]/u', '', $string); Вы просто удаляете символы 0-31 и 127. Данная конструкция будет работать как для UTF-8, так и для 8-битного ASCII, так как второе является подмножеством первого и они обе имеют одни и те же диапазоны управляющих символов. Откровенно говоря, такая конструкция будет работать и без /u, но он сделает вашу жизнь легче, если вам будет необходимо удалять и какие либо другие символы... Если же вы имеете дело в Unicode, то в нем очень много непечатных символов, но давайте рассмотрим один, самый часто употребимый: NO-BREAK SPACE (U+00A0) В строке UTF-8, он может быть представлен как 0xC2A0. Соответственно вам будет необходимо искать и удалять эту последовательность символов, но, если вы использовали модификатор /u, вы можете просто указать \xA0: $string = preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $string); Бонус: а что если str_replace? preg_replace крайне эффективен, но если вам необходимо обработать большое количество текста, то более производительным будет использовать str_replace с указанием ему массива символов: //задаем массив, который будем использовать во всех своих операциях замены $badchar=array( // Управляющие символы chr(0), chr(1), chr(2), chr(3), chr(4), chr(5), chr(6), chr(7), chr(8), chr(9), chr(10), chr(11), chr(12), chr(13), chr(14), chr(15), chr(16), chr(17), chr(18), chr(19), chr(20), chr(21), chr(22), chr(23), chr(24), chr(25), chr(26), chr(27), chr(28), chr(29), chr(30), chr(31), // Непечатные символы chr(127) ); //Удаляем нежелательные символы $str2 = str_replace($badchar, '', $str); Интуитивно кажется, что данный подход будет работать сильно быстрее, но давайте проведем тесты. Создадим набор тестовых строк различной длины и содержания и проверим скорость работы (использовался PHP 7.0.12): 2 chars str_replace 5.3439ms preg_replace 2.9919ms preg_replace is 44.01% faster 4 chars str_replace 6.0701ms preg_replace 1.4119ms preg_replace is 76.74% faster 8 chars str_replace 5.8119ms preg_replace 2.0721ms preg_replace is 64.35% faster 16 chars str_replace 6.0401ms preg_replace 2.1980ms preg_replace is 63.61% faster 32 chars str_replace 6.0320ms preg_replace 2.6770ms preg_replace is 55.62% faster 64 chars str_replace 7.4198ms preg_replace 4.4160ms preg_replace is 40.48% faster 128 chars str_replace 12.7239ms preg_replace 7.5412ms preg_replace is 40.73% faster 256 chars str_replace 19.8820ms preg_replace 17.1330ms preg_replace is 13.83% faster 512 chars str_replace 34.3399ms preg_replace 34.0221ms preg_replace is 0.93% faster 1024 chars str_replace 57.1141ms preg_replace 67.0300ms str_replace is 14.79% faster 2048 chars str_replace 94.7111ms preg_replace 123.3189ms str_replace is 23.20% faster 4096 chars str_replace 227.7029ms preg_replace 258.3771ms str_replace is 11.87% faster 8192 chars str_replace 506.3410ms preg_replace 555.6269ms str_replace is 8.87% faster 16384 chars str_replace 1116.8811ms preg_replace 1098.0589ms preg_replace is 1.69% faster 32768 chars str_replace 2299.3128ms preg_replace 2222.8632ms preg_replace is 3.32% faster Замеры производились для 10.000 итераций. Тут очень интересно посмотреть на относительные различия. Для строк длиной до 512 символов со значительным отрывом побеждает preg_replace. В диапазоне 1-8kb разница нивелируется. Интересный результат, не правда ли? Но в любом случае не стоит всецело полагаться на мои тесты, так как на ваших конкретных данных все может быть ровно наоборот.

Ответ 3



На самом деле, посмотрите в сторону расширения INTL Там есть, например, такое IntlChar::isprint — Проверяет, является ли симвом отображаемым

пятница, 24 января 2020 г.

Как заставить python понимать unicode. При чтении из файла ошибка: UnicodeDecodeError: 'charmap' codec can't decode byte

#python_3x #файлы #unicode


Приветствую! Как заставить питон читать из файла и выводить любые юникод символы?Типа
такого всякого разного.  ←↑→↓↔↕↖↗↘↙↚↛↜↝↞↟. 
При попытке просто прочитать 

# -*- coding: utf-8 -*-
f = open("unicode_symbols.txt", "r")
        for s in f:
            print(u""+s)
            print("\n")


выводит следующую ошибку

  return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x98 in position 18: character
maps to 

    


Ответы

Ответ 1



попробуйте для начала указать кодировку файла при чтении явно. f = open("unicode_symbols.txt", "r", encoding = 'utf-8') и - все получится! Ну если не верите - попробуйте еще такой код: # BEGIN NUMERICS_DEMO import unicodedata sample = '1\xbc\xb2\u0969\u136b\u216b\u2466\u2480\u3285' f = open("F:\\PyCodes\\WOW\\utf8_rows.txt", "r+", encoding='utf-8') for char in sample: _ = 'U+%04x' % ord(char) + char.center(6) + unicodedata.name(char) f.write(_) for s in f: print(u""+s) # END NUMERICS_DEMO Ну понятное дело - путь к своему файлу нарисуйте =D У меня на печати это: U+0031 1 DIGIT ONE U+00bc ¼ VULGAR FRACTION ONE QUARTER U+00b2 ² SUPERSCRIPT TWO U+0969 ३ DEVANAGARI DIGIT THREE U+136b ፫ ETHIOPIC DIGIT THREE U+216b Ⅻ ROMAN NUMERAL TWELVE U+2466 ⑦ CIRCLED DIGIT SEVEN U+2480 ⒀ PARENTHESIZED NUMBER THIRTEEN U+3285 ㊅ CIRCLED IDEOGRAPH SIX

четверг, 9 января 2020 г.

Включение Unicode при использовании WinAPI

#c #windows #winapi #unicode


Для включения режима Юникода в WinAPI требуется два определения:

#define UNICODE
#define _UNICODE


Подскажите, зачем нужно два определения, чем они отличаются и бывают ли ситуации,
когда нужно одно, но не другое?
    


Ответы

Ответ 1



UNICODE используется заголовочными файлами Windows, а _UNICODE - заголовочными файлами C-runtime и MFC.

понедельник, 6 января 2020 г.

Как получить файл (кириллица в имени) с FTP?

#python #python_3x #ftp #unicode


Python 3.5, ftplib

В каком виде ftp.nlst() получает имена файлов? И как их привести к нормальному виду?

filelist = ftp.nlst()   - получаем список имен файлов
print (filelist[3])     - выводим имя 4-ого файла и получаем иероглифы


@jfs >>> print(ascii(filelist[6])) '\xc8\xed\xf1\xf2\xf0\xf3\xea\xf6\xe8\xff.pdf'

Спасибо за подробный ответ)
    


Ответы

Ответ 1



Изначально (RFC 765, 959), FTP только 7-бит ASCII поддерживал, RFC 2640 расширяет поддержку до других кодировок, RFC 3659 уточняет, что команды такие как MLST могут вернуть пути либо в UTF-8 кодировке, либо это может быть произвольная каша байтов—за некоторыми исключениями такими как CRLF (новая строка, b'\x0d\x0a'), одинокий Telnet IAC (b'\xff'). На POSIX имена файлов могут быть произвольной последовательностью байтов за исключением b'\x2f' и b\x00' (слэш и ноль). В Питоне 3, ftplib формально использует latin-1 кодировку по умолчанию, которая произвольную последовательность байт позволяет в Unicode декодировать. В: В каком виде ftp.nlst() получает имена файлов? ftp.nlst() возвращает список текстовых (Unicode) строк. В: И как их привести к нормальному виду? Если вы знаете, что сервер использует единственную кодировку для имён файлов в вашем случае (вероятно, utf-8, если вывод команды feat её показывает) и нет непредставимых имён (PEP 383), то правильные имена можно получить декодированием: filename = filename.encode(ftp.encoding).decode(your_encoding) Можно передать 'surrogateescape' обработчик ошибок в .decode(), чтобы поддерживать и непредставимые имена (чтобы была возможность без потерь восстановить изначальные байты, одновременно позволяя печатать представимые имена в «нормальном виде»). Судя по результату ascii(), в вашем случае ftp-сервер возвращает имена в cp1251 кодировке (ANSI codepage на русской Винде): >>> print(ascii(filelist[6])) '\xc8\xed\xf1\xf2\xf0\xf3\xea\xf6\xe8\xff' В этом случае, your_encoding='cp1251', чтобы получить исходное имя: filename = filelist[6].encode(ftp.encoding).decode('cp1251') # -> 'Инструкция' Чтобы зря не перекодировать, можно перед вызовом ftp.nlst() выставить ftp.encoding = 'cp1251', если известно что все имена файлов в этой кодировке представимы. Тогда ftp.nlst() сразу вернёт правильно декодированные имена.

вторник, 31 декабря 2019 г.

регулярное выражение (re) для строки на русском языке: найти три буквенно-цифровых символа с последующей точкой

#python #регулярные_выражения #кодировка #unicode #python_27


Python 2.7.6 
проблема с применением re к строке на русском.


задача - найти три буквенно-цифровых символа с последующей точкой;
код: 

#!/usr/bin/python
# -*- coding: utf-8 *-*
import re
new = re.findall("\w{3}\.", "gth. Ср. дек.  7 21:22:29 EET 2016" )
print new

результат >> ['gth.']
вопрос: почему игнорируется 'дек.'?

    


Ответы

Ответ 1



Используйте Unicode-строки и флаг re.UNICODE: #!/usr/bin/env python2 # -*- coding: utf-8 *-* import re pattern = re.compile(ur"\w{3}\.", re.UNICODE) match = pattern.findall(u"gth. Ср. дек. 7 21:22:29 EET 2016") print(match) for i in match: print(i) Результат: [u'gth.', u'\u0434\u0435\u043a.'] gth. дек.

Разделение строки по разделителю и преобразование в числа

#python #файлы #кодировка #unicode


День добрый!

Есть .txt файл который содержит строки вида: 

8415778000|8415778099


Мне нужно записать все числа а промежутке от 1-го числа до 2-го. Я написал вот такой
скрипт. 

f = open('pool.txt')
for line in f.readlines():
    a, b = line.split('|', 1)
    b = int(b.strip())
    a = int(a.strip())
    print (str(a))
    while a <= b:
        a += 1
        print(str(a))


Но при выполнении он выдает ошибку:

>     Traceback (most recent call last):    
      File "*/1.py", line 5, in     
       a = int(a.strip())    
    ValueError: invalid literal for int() with base 10: '\xef\xbb\xbf8415778000'


Я не могу понять почему, помогите.
    


Ответы

Ответ 1



Примените параметр encoding='utf_8_sig' в функции open(): f = open('pool.txt', encoding='utf_8_sig') так как ваш файл кодирован в кодировке UTF-8 s BOM (BOM - Byte Order Mark), где первые 3 байты всегда те же самые (для обозначения вот этой кодировки). Примечание: Вместо f = open('pool.txt', encoding='utf_8_sig') for line in f.readlines(): a, b = line.split('|', 1) .... .... лучше писать with open('pool.txt', encoding='utf_8_sig') as some_name: for line in some_name: a, b = line.split('|', 1) .... .... т.к. после выхода из блока with будет файл автоматически закрыт (кроме других преимуществ).

Ответ 2



\xef\xbb\xbf - это Маркер последовательности байтов Можно попробовать следующее: f = open("pool.txt") data = f.read().decode("utf-8-sig").encode("utf-8")

Почему Marshal.SizeOf возвращает 1 байт для переменной типа char?

#c_sharp #net #unicode #char #sizeof


Приведу код:

char charVal = '૧'; // код 0AE7
Console.WriteLine(sizeof(char)); // 2

Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(charVal)); // 1?


Здесь объявляем переменную типа char и пытаемся выяснить ее размер. Как видно, для
размера типа результат будет 2, тогда как для переменной результат будет 1. Что-то
находил по поводу того, что результат Marshal.SizeOf(charVal) зависит от установленного
значения CharSet, но так и не понял, как управлять всем этим. 

По идее, я указал в коде символ юникода, поэтому символ должен занимать 2 байта,
но оказывается, что это не так. Почему?
    


Ответы

Ответ 1



Короткий ответ: Потому что по-умолчанию (если не указана кодировка) символы маршалируются в ANSI. При этом кодировку можно установить с помощью [StructLayout] и [DllImport] (Default Marshaling for Characters): When a managed Char type, which has Unicode formatting by default, is passed to unmanaged code, the interop marshaler converts the character set to ANSI. You can apply the DllImportAttribute attribute to platform invoke declarations and the StructLayoutAttribute attribute to a COM interop declaration to control which character set a marshaled Char type uses. Использовать Marshal.SizeOf имеет смысл только при взаимодействии с неуправляемым кодом. Результат для char мало что означает. Длинный ответ: Вроде выковырял описание этого поведения из документации. В документации Marshal.SizeOf говорится, что для символов результат определяется установленным CharSet: ... For character types, the size is affected by the CharSet value applied to that class. ... Что это означает? Это означает, что если тип char используется в структуре, то размер, который для символа вернет SizeOf определяется свойством CharSet атрибута StructLayout: [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] public struct OneByte { public char ch; //1 } [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] public struct TwoByte { public char ch; //2 } Теперь осталось выяснить какая проставлена кодировка для структуры System.Char. В документации использованный атрибут явно не указан, но указывается, что по умолчанию используется ANSI: Char values and interop When a managed Char type, which is represented as a Unicode UTF-16 encoded code unit, is passed to unmanaged code, the interop marshaler converts the character set to ANSI by default. You can apply the DllImportAttribute attribute to platform invoke declarations and the StructLayoutAttribute attribute to a COM interop declaration to control which character set a marshaled Char type uses. Для верности проверяем исходный код Char: [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)] public struct Char Как видим CharSet не задан, соответственно, он принимает значение по умолчанию. В документации указывается LPSTR (однобайтный тип): Indicates whether string data fields within the class should be marshaled as LPWSTR or LPSTR by default. Но опять для верности проверяем код StructLayoutAttribute и выясняем что по умолчанию используется CharSet.None: CharSet charSet = CharSet.None; switch (type.Attributes & TypeAttributes.StringFormatMask) { ... Который, согласно документации, устарел и эквивалентен Ansi. Marshal.SizeOf скорее всего просто проверяет значение кодировки в атрибуте и возвращает на его основании 1. Этот результат имеет мало смысла т.к. Char не будет маршалится как отдельная структура В практических сценариях маршалинга будет использоваться кодировка, заданная для конкретной структуры. В процессе поиска нашел актуальную цитату из старой книги .NET and COM: The Complete Interoperability Guide Адама Натана: Caution Never use Marshal.SizeOf to determine the "real size" of a managed type, because the results can be misleading. Just think of Marshal.SizeOf as Marshal.UnmanagedSizeOf. An appropriate use of Marshal.SizeOf is to fill a struct's "size field" when passing it to unmanaged code. ... Furthermore, you should never use Marshal.SizeOf with the System.Char type to determine the current platform's character size — use Marshal.SystemDefaultCharSize instead. This is because Marshal.SizeOf always reports 1 for the size of the System.Char type regardless of platform due to an extremely subtle reason. It reports the size of the System.Char value type in the mscorlib assembly, which has a single character field. Because the definition is marked with CharSet.Ansi, the structure would have a size of 1 byte if marshalled to unmanaged code as a plain struct. ... But because the System.Char type is treated specially as a character primitive type, it is never passed as a plain struct to unmanaged code. By default, character parameters and return types are marshalled as 2-byte Unicode characters, and character fields in a structure are marshalled depending on the structure's character set. Note that doing sizeof(char) in C# unsafe code always returns 2 regardless of platform because .Net characters are always Unicode. Не уверен насчет маршалинга параметров и возвращаемых значений, но остальная информация вроде бы не устарела.

Как выводить на экран и вводить данные типа wchar_t[]?

#c #windows #unicode #mingw


Вопрос в том, как это сделать на Windows. На Linux-е это просто

setlocale(LC_CTYPE, "");
//а потом wprintf ...


На Windows такое не катит.
Желательно, чтобы вышло как-то так.

#ifdef __linux__ 
  setlocale(LC_CTYPE, "");
#elif defined _WIN32
  //Windows
#else


Нужно для вывода кириллицы, иероглифов и т. п.
Нужен именно wchar_t.

P. S. MinGW gcc -dumpversion 4.8.1

P. P. S. На MS Visual C++ 2010 работает ответ 1 (без stdafx.h)
    


Ответы

Ответ 1



Нужно вызвать _setmode(_fileno(stdout), _O_U16TEXT); #include #include #include int wmain(int argc, wchar_t* argv[]) { _setmode(_fileno(stdout), _O_U16TEXT); std::wcout << L"Testing unicode -- English -- Ελληνικά -- Español." << std::endl; // или wprintf(L"Testing unicode -- English -- Ελληνικά -- Español.\n"); return 0; } Поддержка конкретных символов зависит от шрифта консоли. Lucida Console и Consolas справляются со всем, кроме иероглифов. Решение взято из ответа на en-SO - Output unicode strings in Windows console app

Ответ 2



Традиционно поддержка Unicode в консоли Windows очень слаба, и вероятно для Windows вам стоит задуматься о графическом интерфейсе (в нём как раз обычно всё в порядке). В «свежих» версиях Visual Studio рантайм стал умнее, и с поддержкой Unicode стало лучше. Тем не менее, вам нужен как минимум шрифт, поддерживающий Unicode (например, Lucida Console). Например, мой экземпляр Visual Studio 2013 с вот таким исходником: #include "stdafx.h" #include #include #include int main(void) { _setmode(_fileno(stdout), _O_U16TEXT); wprintf(L"%s", L"кошка \x65e5\x672c\x56fd\n"); return 0; } выдал на экран кириллицу, но не иероглифы. При редиректе вывода в файл, однако, всё читается правильно. (Это означает, что проблема в шрифте.) С выводом RTL-текстов (иврит, арабский), однако, всё ещё возможны проблемы. Информация взята отсюда. (Ответ относится к toolchain'у Visual Studio.)

Ответ 3



О мой бог, cygwin мне помог... -- говорил когда-то святой Георгий. Cygwin выручил и меня! #ifdef __linux__ setlocale(LC_CTYPE, ""); #elif defined _WIN32 //Windows #else Теперь и этого не надо! Просто setlocale(LC_CTYPE, ""); Работает и на Linux, и на Windows (cygwin1.dll). Версия компилятора g++: 4.9.2. Версия Windows: XP SP3.

C++ - некорректное определение отдельного символа в строке

#cpp #linux #unicode #char


Всем привет!
Проблема заключается в следующем - имеются Linux с Code:Blocks IDE и g++ в качестве
компилятора, программный код C++, а так же символьная строка (string либо char []),
которой присваивается текст в кириллических символах. При выводе всей строки, выводимый
текст в консоли отображается нормально. Но если обращаться к любому отдельному элементу
строки, то вместо символа выводится вопросительный знак на фоне ромба и я так понимаю,
что сама программа не может определить - какой это символ, так как условный оператор
на него не реагирует. Кодировка естественно - Unicode (UTF-8).  

#include 
#include 

using namespace std;

int main ()
{
  string word = "Слово";
  cout << word; //нормально выводится "Слово"
  cout << word [0]; //выводится '?'
  if (word [0] == "С") cout << word [0]; //оператор if считает, что false
  return 0;
}    


UPD: в общем и целом мне не нужна была большая программа, поэтому я просто создал
отдельную строку, к которой присваивается необходимая пара элементов проверяемой строки
содержащая один нужный символ ([0], [1]; [2], [3] и тд). Полученную строку вполне удаётся
использовать в условных операторах:

#include 
#include 

using namespace std;

int main ()
{
 string word = "Слово", letter;
 letter += word [0];
 letter += word [1];
 if (letter == "С") cout << letter;//true, выводится "С"
 return 0;
}


Разумеется, это выглядит топорно, но на мой взгляд это самый простой способ в контексте,
скажем например, университетской лабораторной работы.
Спасибо всем за помощь и полезную информацию (=
    


Ответы

Ответ 1



Кодировка UTF-8 это многобайтовая кодировка, один символ может кодироваться несколькими байтами. В частности русские буквы кодируются двумя байтами, например 'ы' кодируется как "\xd1\x8b". Когда Вы пытаетесь напечатать один байт закодированной буквы, например "\xd1" или "\x8b", то выводится как знак вопроса, потому что это не валидная UTF-8 строка.

Ответ 2



В качестве альтернативного решения, если вам нужна работа с отдельными символами, и вы уверены, что вам не придётся работать с экзотикой наподобие символов Unicode, лежащих за главной плоскостью, попробуйте перевести вашу программу на широкие строки: wstring word = L"Слово"; wcout << word; wcout << word[0]; if (word[0] == L'С') wcout << word[0]; Это повысит расход памяти, но избавит вас от великого и ужасного ICU. Тем не менее, это оставляет вас наедине с возможной диакритикой (акценты наподобие точек и крючочков у ü или там ç всё равно занимают отдельный wchar_t). В C++ нет строк, смиритесь. Всё вручную. Да, и убедитесь, что ваша консоль работает в нужном режиме (это системно-зависимая вещь).

Ответ 3



В общем и целом, мне не нужна была большая программа, поэтому я просто создал отдельную строку, к которой присваивается необходимая пара элементов проверяемой строки содержащая один нужный символ ([0], [1]; [2], [3] и тд). Полученную строку вполне удаётся использовать в условных операторах: #include #include using namespace std; int main () { string word = "Слово", letter; letter += word [0]; letter += word [1]; if (letter == "С") cout << letter;//true, выводится "С" return 0; } Разумеется, это выглядит топорно, но на мой взгляд это самый простой способ в контексте, скажем например, университетской лабораторной работы. Спасибо всем за помощь и полезную информацию (=

пятница, 27 декабря 2019 г.

C++11 string literal u8

#cpp #unicode


Решил написать небольшой пример:

#include 

int main()
{
    std::cout << u8"это строка6" << std::endl;
    return 0;
}


Устанавливаю в консоли кодовую страницу с помощью следующей команды:
chcp 65001

Выполняю программу, и получаю следующий вывод:

��то строка6


Почему первый символ отобразился неправильно?
Судя по выводу, при использовании литерала u8, BOM в начало не добавляется.
Это кодировка 65001 думает, что в начале идет BOM, пытается прочитать его,
а остальное выводит нормально. Тогда хотелось бы найти кодировку UTF-8 без BOM.

Дополнения:
Файл сохранен также в utf8 without BOM. Если перенаправить в файл, то запишется нормально.
Компилятор Mingw с версией gcc 5.0. Система - Windows.
    


Ответы

Ответ 1



Советую вам не использовать utf-8 при выводе в консоль на Windows (режим utf-8 имеет баги), вместо этого пользоваться "широкими" потоками (подробнее про использование юникода в Windows) #include #include #include #include #include // std::wcerr std::wstring strtows(const std::string &str, UINT codePage) { std::wstring ws; int n = MultiByteToWideChar(codePage, 0, str.c_str(), static_cast(str.size()), NULL, 0); if (n) { ws.resize(n); if (MultiByteToWideChar(codePage, 0, str.c_str(), static_cast(str.size()), &ws[0], n) == 0) ws.clear(); } return ws; } std::string wstostr(const std::wstring &ws, UINT codePage) { // prior to C++11 std::string and std::wstring were not guaranteed to have their memory be contiguous, // although all real-world implementations make them contiguous std::string str; int srcLen = static_cast(ws.size()); int n = WideCharToMultiByte(codePage, 0, ws.c_str(), srcLen, NULL, 0, 0, NULL); if (n) { str.resize(n); if (WideCharToMultiByte(codePage, 0, ws.c_str(), srcLen, &str[0], n, 0, NULL) == 0) str.clear(); } return str; } std::string WstringToUtf8(const std::wstring &str) { return wstostr(str, CP_UTF8); } std::wstring Utf8ToWstring(const std::string &str) { return strtows(str, CP_UTF8); } int main(int argc, char *argv[]) { _setmode(_fileno(stdout), _O_U16TEXT); std::wcout << Utf8ToWstring(u8"это строка6") << std::endl; return 0; }

среда, 25 декабря 2019 г.

Как использовать сообщения в unicode в assert-методах?

#python #кодировка #юнит_тесты #unicode


Не могу добиться, чтобы методы assert корректно выводили сообщения в юникоде:

# coding=utf-8
from unittest import TestCase

class Example(TestCase):

    def test_mcve(self):
        message = u'Привет, мир!'
        print message
        self.assertTrue(False, message)


Результат выполнения:

Testing started at 17:07 ...
Привет, мир!

Failure
Traceback (most recent call last):
  File "/home/n.volynkin/example/mcve.py", line 9, in test_mcve
    self.assertTrue(False, message)
AssertionError: \u041f\u0440\u0438\u0432\u0435\u0442, \u043c\u0438\u0440!


То есть просто так строка корректно выводится в stdout, а из ассерта - ломается юникод.
Как получить нормальные строки?
    


Ответы

Ответ 1



Совершенно неожиданно я нашёл ответ: class Example(TestCase): def test_mcve(self): message = u'Привет, мир!' print message self.assertTrue(False, message.encode('utf-8')) Источник: https://stackoverflow.com/a/14181711/2790048 Когда пойму магию юникода в Python, дополню ответ.

суббота, 21 декабря 2019 г.

Длина строки считается неверно: unicode в python 2.7

#python #строки #python_2x #unicode


Вычисляю длину строки. Но длина строки (наверное), считается удвоенной для русских
символов. Для цифр -- нет. Например:

len("ул Весёлая") == 1 + 2 * 9 // (Пробел + русские символы (*2))
len("ул Весёлая 71") == 1 + 2 * 9 + 1 + 3 // (Пробел + русские символы (*2) + пробел
+ 2 цифры)


Есть ли функция в питоне, которая считает истиную длину строки, а не количество байтов
(считается, наверное, именно кол-во байтов).
    


Ответы

Ответ 1



Проблема не возникает, если использовать правильные(unicode) строки: >>> print(len('ул Весенняя 13')) 24 >>> print(len(u'ул Весенняя 13')) 14 Можно самостоятельно декодировать простые строки: >>> print(len('ул Весенняя 13'.decode("utf-8"))) 14 В python3 нет такой проблемы, потому что строки по умолчанию в utf-8: >>> print(len('ул Весенняя 13')) 14 >>> print(len(u'ул Весенняя 13')) 14 В общем случае(полный набор символов unicode) задача найти длину строки не является тривиальной. Во первых, нужно определиться с самим термином - что понимать под длиной строки? Варианты: количество байт в utf-8 представлении (24 выше) количество unicode символов (14 выше) можно посчитать, как количество всех байт, кроме диапазона (0x80-0xBF). количество видимых знаков количество занятых знакомест Нужно исключить диакритику и прочие символы, не занимающие места Положение усугубляется ещё и тем, что одни и те же строки могут быть закодированы разными последовательностями unicode codepoints. Для определённости можно "нормализовать" строку, например, с помощью unicodedata.normalize('NFC', ustr) >>> len(regex.findall(ur'[\0-\u02FF\u0370-\u1DBF\u1E00-\u20CF\u2100-\uD7FF\uDC00-\uFE1F\uFE30-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF][\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]', unicodedata.normalize('NFC', u'Z͑ͫ̓ͪ̂ͫ̽͏̴̙A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘!̿̋ͥͥ̂ͣ̐́́͞'))) 6

Ответ 2



Константы (string literals) "" создают байтовые строки в Питоне 2 (если from __future__ import unicode_literals не включено). Поэтому len("abc") возвращает количество байт. u"" является строковой константой, которая всегда Unicode строки создаёт. len(u"abc") вернёт количество Юникодных символов (Unicode codepoint). Некоторые буквы (user-perceived characters) могут состоять из нескольких символов. В этом случае, можно \X регулярное выражение использовать, чтобы найти количество "неразрывных/слитных" элементов текста (eXtended grapheme clusters): >>> import regex # $ pip install regex >>> text = u'я 😂 ё' >>> print(repr(text)) u'\u044f \U0001f602 \u0435\u0308' # 6 code points >>> regex.findall(ur'\X', text) # 5 grapheme clusters [u'\u044f', u' ', u'\U0001f602', u' ', u'\u0435\u0308'] >>> print " | ".join(regex.findall(ur'\X', text)) я | | 😂 | | ё # 5 user-perceived characters Дополнительно, существуют так называемые узкие сборки Питона 2, в которых не BMP-символы такие как 😂 представляются в виде utf-16 суррогатной пары (surrogate pair) — нарушение абстракции, что Юникодная строка является неизменяемой последовательностью Unicode сodepoint. Вот ещё пример одного знака (emoji), который из нескольких юникод-cимволов состоит: >>> emoji = u'\U0001f469\u200d\U0001f469\u200d\U0001f467\u200d\U0001f466' >>> print(emoji) 👩‍👩‍👧‍👦 >>> len(emoji) 7 >>> len(regex.findall(u'\X', emoji)) 1 С точки зрения движения курсора, выделения, копирования, итд — этот эмодзи это один GUI элемент. Как разбить строку на отдельные символы? Разделить в Python 3 слово на символы Для текстовых интерфейсов может иметь значение ширина напечатанной строки в терминале. python-prompt-toolkit использует wcwidth модуль: >>> import wcwidth # $ pip install wcwidth >>> wcwidth.wcswidth(emoji) 8

Проблемы с кодировкой при парсинге некоторых сайтов, Golang

#кодировка #парсер #golang #unicode


Доброго времени суток. Столкнулся с такой проблемой: некоторые сайты парсятся адекватно
- текст из формочек достается в читабельной кодировке, а некоторые - нет.
Сначала грешил на UTF-8 на сайте, но ведь Go искаропки только с UTF-8 и работает
по-дефолту
Получаю странику таким кодом: 

func FetchHTML(url string) (string, bool){
    page := ""
    resp, HttpErr := http.Get(url)
    if HttpErr != nil {
        err := HTTPError{url, "", HttpErr.Error()}
        fmt.Println(err.Error())
        return "", false
    }

    defer resp.Body.Close()
    body, IoErr := ioutil.ReadAll(resp.Body)
    if IoErr != nil {
        fmt.Println("IO error: ", IoErr.Error())
        return "", false
    }

    fmt.Println(body)
    page = string(body)
    fetched = true
    return page, true
}


Примеры:
Например, спарсим цитату из любимого всеми ithappens.
Передаю парсеру страничку по адресу http://ithappens.me/story/623
Получаем:

#623
КПД 100%
26 февраля 2009, 11:00

Приятель-программист поделился историей: написал для внутреннего пользования бенчмарк
— в шестнадцати потоках перемножаются здоровенные матрицы. Все скомилировалось, запустилось
и заработало, причем не просто быстро, а слишком быстро.
Матрицы перемножались мгновенно!
После разбора причин происходящего выяснилось, что тестовые матрицы представляли
из себя массивы нулей. Умный интеловский компилято решил не загружать процессор перемножением
и сложением нулей и оптимизировал код таким образом, чтобы сразу заполнить матрицы
необходимого размера нулями.

Rating: 1866
Tags: чудеса техники, программы


Теперь пытаемся сделать то же самое, например, с http://bash.im/quote/435048 
Получаем:

#435048
2015-08-06 12:13
���: �� �������� ���� �������� ������, ��������� 15 ��� ������
���: ����� �������: ����, �� �� �����, �� ��� �� ������
���: �� ���, �� � ����. ��� � �� �����, � ����� ������� ����.
���: ���� �������, � ��� ��� ����� ��� ������ �����, �������� ������������ �� ������
��������� ����� ������ ������
���: �� � � ������� �������, �������� - ���� �������������, ���������.     �������������.
������: ���� �����, 158, 161, 162 (�����, ������, ������), ��������� ��� ��� �� ��������
- ���� ����� ������� �� ������ �� ����������. (�� ����� ���� - �����, ����� ����� ��
���� � ������ ������ ������). �, ������, ���������, �� ��� ��� � �� �������.
���: ��� ��������, ��������
���: � ��� �������, ��� �� ��� ������.
���: ��������� ���������. ��������� �� ���������, �� 4 �����, ������� � ���� - ������
������. ���� ������� �� �����, ������������ ������ - ����� ��� � �������� �����. ���,
��, ����� ����, ����� ����... ���� ����, ��� ���� �������� � ���� �����, ��� ��� �
� ����� ����� ���� ����� ����� ��. � ������: ��-�������, ���� �������� �������.
���: ����!!! � � ���� ��������, �� ������� ������, �� �������!!!
Rating:


Заметил, что в то время как байты текста с ithappens имеют значение 1??, байты текста
bash.im переваливают в значениях за 200.
В чем может быть проблема и как ее решить?
    


Ответы

Ответ 1



Я рекомендую использовать пакет golang.org/x/net/html/charset и собственно его функцию NewReader. Эта функция принимает собственно io.Reader и заголовок Content-Type если он есть. Функция анализирует Content-Type и первые 1024 байта тела и возвращает io.Reader в кодировке UTF-8, а так же ошибку, если она имеет место. Всё просто и круто. Для примера: package main import ( "fmt" "golang.org/x/net/html/charset" "io/ioutil" "net/http" ) func main() { url := "http://bash.im/quote/435048" resp, err := http.Get(url) if err != nil { fmt.Println("HTTP error:", err) return } defer resp.Body.Close() // вот здесь и начинается самое интересное utf8, err := charset.NewReader(resp.Body, resp.Header.Get("Content-Type")) if err != nil { fmt.Println("Encoding error:", err) return } // оп-па-ча, готово body, err := ioutil.ReadAll(utf8) if err != nil { fmt.Println("IO error:", err) return } fmt.Println(string(body)) } Чем хорош этот способ - тем, что он универсален. Можно спокойно применять его для любого сайта. И нет нужды ковыряться в тегах вроде golang кодировка парсер

Ответ 2



Посмотрите на код того же bash.im'а: Страница в кодировке Windows-1251. Чтобы перевести в UTF-8, пользуйтесь пакетами из golang.org/x/text. Например: dec := charmap.Windows1251.NewDecoder() // Разные кодировки = разные длины символов. newBody := make([]byte, len(body)*2) n, _, err := dec.Transform(newBody, body, false) if err != nil { panic(err) } newBody = newBody[:n]

пятница, 20 декабря 2019 г.

Знак рубля не отображается в Android приложении

#android #qt #unicode


Вот он герой моего вопроса - ₽. 
Вместо него в приложении отображается симпатичный квадратик. Это знак начал неожиданно
возвращаться из Google Play Billing Library вместе с ценой (in-app billing). Покупатели
в панике. Приложение написано на C++ и Qt.

Устройство - какойто там сумсанг с андроидом 4.4.2

Как его можно отобразить?

p.s. в Google Play тоже не отображается
    


Ответы

Ответ 1



Не знаю, исследовали ли вы эту тему или нет, но символ рубля появился сравнительно недавно (по сравнению c $), и далеко не во всех шрифтах он есть. Поэтому, вы далеко не первый, кто сталкивается с проблемой отображения символа рубля. Самое, на мой взгляд, простое P // P Использовать картинку: https://commons.wikimedia.org/wiki/File:Ruble_sign.svg Использовать шрифт от Лебедева: http://www.artlebedev.ru/tools/technogrette/html/rouble/ *больше информации по этому вопросу: https://stackoverflow.com/questions/20665622/russian-ruble-symbol-html-code

Ответ 2



Вот шрифт, в котором после последнего январского обновления добавился символ рубля.