Страницы

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

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

вторник, 31 марта 2020 г.

Почему добавляются непонятные символы в БД при вводе русских букв (кириллицы) в phpMyAdmin?

#кодировка #utf_8 #кириллица


На странице, в которой ввожу данные, кодировка текста "< meta charset="utf-8>". Ввел
строку "Главная"



Вывод на другой странице выглядит так:



В БД кодировка - utf8_general_ci, а запись этих строк выглядит вот так:


    


Ответы

Ответ 1



Скрипт, который пишет в БД, не установлена кодировка обмена с mysql. В итоге скрипт пишет в БД в кодировке по умолчанию (скорее всего Latin). Поскольку и читает он в этой же кодировке, то на сайте все отображается как надо, а вот в phpMyAdmin, настроенном на utf8, вы видите "кракозябры". В скрипте, после соединения с БД надо выполнить запрос SET NAMES utf8 чтобы установить нужную кодировку обмена с БД

среда, 26 февраля 2020 г.

Как победить искажение текста кирилицы в bash, запущенном в Docker-контейнере?

#docker #кириллица #locale


Настроил локаль для контейнера:

# Set the russian locale
RUN apt-get clean && apt-get update && apt-get install -y locales
RUN locale-gen ru_RU.UTF-8
ENV LANG ru_RU.UTF-8
ENV LANGUAGE ru_RU.UTF-8
ENV LC_ALL ru_RU.UTF-8


При этом русский текст в bash терминале все-равно работает неправильно: ввод начинается
с символа ":�", вставка текста на русском выгляди точно также (начало строки искажается
при вставке). Как бы справиться с этой проблемой?
    


Ответы

Ответ 1



Пример из рабочего Dockerfile, проверено и работает. FROM php:7.2-apache RUN apt-get update && apt-get install -y locales # Locale RUN sed -i -e \ 's/# ru_RU.UTF-8 UTF-8/ru_RU.UTF-8 UTF-8/' /etc/locale.gen \ && locale-gen ENV LANG ru_RU.UTF-8 ENV LANGUAGE ru_RU:ru ENV LC_LANG ru_RU.UTF-8 ENV LC_ALL ru_RU.UTF-8 # +Timezone (если надо на этапе сборки) ENV TZ Europe/Moscow RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

Ответ 2



вероятно, в образе, используемом вами, не сгенерирована такая локаль (ru_RU.UTF-8). посмотрите список командой locale -a (приведён пример вывода): $ docker run --rm -ti имя-образа locale -a C C.UTF-8 POSIX для нормальной работы с кириллицей вполне подойдёт имеющаяся локаль C.UTF-8: $ docker run --rm -ti -e LC_ALL=C.UTF-8 ubuntu:16.04 bash если же необходима именно русскоязычная локаль, то её надо сгенерировать. наиболее, пожалуй, универсальный способ — использовать скрипт locale-gen: $ locale-gen ru_RU.UTF-8 Generating locales (this might take a while)... ru_RU.UTF-8... done Generation complete. скрипт этот присутствует (в debian-основных дистрибутивах) в пакет locales, который в вашем образе, скорее всего, тоже отсутствует, и его надо установить. демо-пример для проверки: $ docker run --rm -ti -e LC_ALL=ru_RU.UTF-8 ubuntu:16.04 bash -c 'apt update && apt install -y locales && locale-gen ru_RU.UTF-8; bash'

суббота, 8 февраля 2020 г.

Функция mail(): трудности с кодировкой

#email #php #кириллица #utf_8 #кодировка


Всем доброго времени!  
Когда все было в windows-1251, все работало нормально. Иероглифы в письме появились,
после того как перевел все на utf-8.
Коды скриптов в utf-8, в html head meta http-equiv="Content-Type" content="text/html;
charset=utf-8".
Похожие темы гуглил, ничего пока не помогло. Использовать в поле From латиницу не
предлагать, т.к. нужна кириллица.
Когда письмо приходит на почту, то в общем списке писем, в поле от кого, кириллица
отображается корректно. Когда заходишь в само письмо, тот же текст в поле от кого,
корректно отображаются только латинские буквы и e-mail отправителя, кириллица выводится
иероглифами. Жирным выделено то, что смущает, в общем списке все нормально, значит,
я отправляю все правильно, но почему в самом письме все меняется?
Также пробовал варианты:

'subject' = '=?koi8-r?B?'.base64_encode(convert_cyr_string("Новое сообщение", "w","k")).'?=';  
'subject' = '=?utf-8?B?'.base64_encode(convert_cyr_string("Новое сообщение", "w","k")).'?=';  
'subject' = '=?koi8-r?B?'.base64_encode("Новое сообщение").'?=';  
'subject' = '=?utf-8?B?'.base64_encode("Новое сообщение").'?=';

На From никак не повлияло.
Код php:

 "tomail@site.ru",  
'subject' => "Новое сообщение",  
'message' => "

Текст сообщения

", 'headers' => "MIME-Version: 1.0\r\n"."Content-type: text/html; charset=utf-8\r\n"."From: Эта кириллица выводится иероглифами \r\n"); mail($mail['to'], $mail['subject'], $mail['message'], $mail['headers']);


Ответы

Ответ 1



Спасибо Stuf, последний комментарий натолкнул на ответ. Подстановки в subject никак не помогли, а вот конвертация только header все решила. Решил следующим образом: "tomail@site.ru", 'subject' => "Новое сообщение", 'message' => "

Текст сообщения

", 'headers' => "MIME-Version: 1.0\r\n"."Content-type: text/html; charset=utf-8\r\n"."From: Эта кириллица выводится иероглифами \r\n"); mail($mail['to'], $mail['subject'], $mail['message'], iconv ('utf-8', 'windows-1251', $mail['headers']));

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

кириллица в термальном принтере

#java #кодировка #кириллица


взял код отсюда http://www.mets-blog.com/java-pos-thermal-printer-example/
там смущает вот эта строка 
bytes = text.getBytes("CP437");
в других кодировках крякозябры в общем как заставить печатать кириллицу?
    


Ответы

Ответ 1



Наверное все носители тайного знания как заставить печатать туповатый принтер кириллицу просто тупо вымерли и я остался один. А ведь были золотые времена в святые 90-е это была вообще золотая тема :) В принтере в евонной памяти содержится некая таблица, в которую загружены шрифты и где напротив байта - стоит его буквенное изображение. Когда принтеру приходит команда печатать байт, он берет байт с ним идет в таблицу извлекает оттуда символ и посылает сигнал своим головкам изобразить символ. Соответственно, задача прогера состоит в том, чтобы шрифты загруженные в память принтера получали правильные байты (кодировка) или же если нет шрифтов загрузить таковые в принтер. Обычно это задача драйвера - драйвер берет на себя эту непосильную задачу. Соответственно, задача распадается в нашем случае на 2 части: Загрузка шрифтов - зависит от модели принтера, обычно в мануале подробно описывается сей процесс (или решается тупо установкой драйвера). В тупых моделях принтеров бывает загружен только 1 шрифт с кодировкой CP-437 (US) Перекодировка байтов (если требуется - зависит от кодировки шрифта) В общем давайте модель принтера - оттуда и будем плясать. Update В мануале расписаны ESC коды управления принтером. По идее, это все должен делать драйвер, но можно и самому. Вам надо сначала перед печатью выставить кодовую страницу, что достигается следующей ESC последовательностью: ESC t n По простому надо в порт принтера записать три байта: 0x1B 0x74 0x11 //байты приведены в HEX (ESC t 17) После чего надо посылать ваш текст, но уже в кодировке KOI-8 Рекомендуется перед этим проинициализировать принтер посылкой команды ESC @

Ответ 2



Кодировка CP437 не содержит кирилицы. Если у вас символы кирилицы закодированны например в русскую кодировку CP1251 или КОИ-8, то на выходе у вас получится набор байт, который нельзя показать ввиду сказанного выше. Поэтому вам скорее всего надо декодировать в другую кодировку, содержащую кирилицу. Но возможен вариант трансфера где декодированные байты можно обратно закодировать с помощью того же CP437 и в результате у вас получится строка в прежней кодировке.

суббота, 11 января 2020 г.

Почему метод onEditorAction не отлавливает нажатие Enter на программной клавиатуре при включенной русской раскладке, но отлавливает его на английской?

#java #android #android_edittext #кириллица


Прочитал на этом сайте и на его английском прародителе много схожих вопросов и ответов,
перепробовал разные условия if, но так и не понял, почему в английской раскладке все
работает так, как я и ожидаю, тогда как в русской - нажатие enter просто переводит
в новую строку (неужели код нажатия клавиши зависит от раскладки?). У EditText задан
атрибут inputType="textMultiLine".    

public boolean onEditorAction(TextView textView, int actionId, KeyEvent event) {

if (event != null) {

if ((event.getKeyCode() == KeyEvent.KEYCODE_ENTER) &&
(event.getAction() == KeyEvent.ACTION_DOWN)) {
            // сохраняем текст, введенный до нажатия Enter в переменную
                currentMessage = editText.getText().toString();
                editText.setText("");
                return true;
        }

    }
    return false;
}


Пробовал менять KeyEvent.ACTION_DOWN на actionId == EditorInfo.IME_ACTION_SEND с
предварительным editText.setImeActionLabel("SEND", EditorInfo.IME_ACTION_SEND);, но
это не помогло.
Заранее благодарю за ответ.
    


Ответы

Ответ 1



Java editText.setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { boolean handled = false; if (actionId == EditorInfo.IME_ACTION_SEND) { currentMessege = editText.getText().toString(); setText(currentMessege); editText.setText(""); handled = true; } return handled; } }); XML Вместо textMultiLine Используйте android:inputType="textImeMultiLine" - проверил лично, работает на все 100% при русской и английской раскладке. Документация P.S. Вкратце, "Enter" на клавиатуре - это imeOptions (Specify the Input Method Action), существуют: IME_ACTION_SEND (картинка письмо) IME_ACTION_DONE (галочка) IME_ACTION_SEARCH (лупа) и т.д в Java нужно обозначать .IME_ACTION_*, в xml android:imeOptions="action*"

воскресенье, 29 декабря 2019 г.

Sqlite игнорировать регистр в условии WHERE

#android #кириллица #sqlite #sql


Подскажите как на андроиде в sqlite базе сделать выборку на кирилице, игнорируя регистр?
запросы с LIKE, COLLATE NOCASE и UPPER(column_name) работают только для английских
букв! А для русских нет!
Для примера, имею таблицу favourite  с записью title = Тест, юзер пытается запросить
её но в поле поиска вводит слово тест маленькими буквами.
пробовал такие варианты:

SELECT * FROM favourite WHERE title LIKE '%тест%'  
SELECT * FROM favourite WHERE UPPER(title) LIKE UPPER('%тест%')  
SELECT * FROM favourite WHERE title LIKE '%ТЕСТ%' COLLATE NOCASE

все три варианта не подходят,  больше ничего не нагуглил. Подскажите пожалуйста решение 
ps: запросы осуществляю так:

SQLiteDatabase db = getWritableDatabase(); //*extends SQLiteOpenHelper*  
Cursor cursor = db.rawQuery(sql, null);
    


Ответы

Ответ 1



Вообще-то это известный баг или фича (кому как) SQLite. Он не понимает case-insensitive where/like/glob, когда символы не в ASCII. Как говорит мануал: A bug: SQLite only understands upper/lower case for ASCII characters by default. The LIKE operator is case sensitive by default for unicode characters that are beyond the ASCII range. For example, the expression 'a' LIKE 'A' is TRUE but 'æ' LIKE 'Æ' is FALSE.) Единственный способ обойти это ограничение, это завести хранимую процедуру выполняющую операцию сравнения. Update Я слегка погорячился по поводу хранимых процедур в SQLite. SQLite не поддерживает хранимые процедуры в общепринятом смысле, нужно писать т.н. custom function на С, пример здесь

Ответ 2



В android такое невозможно. sqlite там собран без ICU, возможность загрузки экстеншнов отключена. Переопределить там ничего не получится, case_sensitive_like тоже бесполезен. Есть несколько обходных вариантов. Добавить в базу ещё одно поле title_lc, в котором хранить то же значение, что и в title, но в нижнем регистре. Преобразование производить на java при помощи String#toLowerCase(Locale.getDefault()) В android sqlite есть 2 нестандартных collator'а: LOCALIZED и UNICODE. Collator указывается в определении столбца при создании БД: CREATE TABLE t1(title TEXT COLLATE LOCALIZED); Сравнение строк будет регистронезависимым (SELECT * where title = "ТеСт";) . Минусы: * COLLATE UNICODE часто не работает; * при использовании COLLATE LOCALIZED нужно указывать локаль для БД: (SQLiteDatabase#setLocale(new Locale("ru_RU"))); * и самый большой минус в том, что LIKE не работает. Воспользоваться не родной сборкой sqlite. Например, sqlcipher можно пересобрать вручную, включив ICU.

Ответ 3



Для SQLite обычно требуется выставить переменную case_sensitive_like PRAGMA case_sensitive_like=OFF; Смотрите результат Можно через костыль SELECT * FROM favourite WHERE UPPER(title) LIKE '%ТЕСТ%' Предварительно тест поднять в верхний регистр на уровне приложения toUpperCase(). Резюме: Для UTF-8 необходимо переопределять LIKE. Есть вариант, как это сделать на PHP (через RegEx-ы). Для Android SDK смотрите в сторону SQLiteDatabase.CustomFunction()

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

is upper для русского языка

#cpp #строки #кириллица


Как проверить первый символ переменной типа std::string на принадлежность к верхнему
регистру с учетом правил русского языка?
Есть что-то готовое или как это сделать ручками?
    


Ответы

Ответ 1



Можно сделать ручками на основе кодов символов Для начала проверяем, лежит ли символ в диапазоне заглавных букв: (letter >= 1040 && letter <= 1071) || letter == 1025 letter == 1025 — отдельная проверка для буквы Ё. Если да, то ничего не делаем, а если нет, то проверяем буква ли это вообще (вдруг там число в начале строки). letter => 1072 && letter <= 1103 // (пока без учёта буквы ё) Напомню, что, когда к типу char применяются операции сравнения или арифметические операции, то работа идёт именно с кодом символа, а не с самим символом. Итак, мы выяснили, что наш символ — это буква в нижнем регистре. Чтобы перевести её в upper case достаточно уменьшить её код на 32, что прекрасно видно из таблицы выше( код A — 1040, код a — 1072; 1072-1040 = 32). char letter = 'a'; letter -= 32; Теперь letter = 'A', что нам необходимо. Осталось отдельно обработать случай с буквой ё, когда: letter == 1105

четверг, 19 декабря 2019 г.

Отображение кириллицы в CLion

#cpp #кириллица #clion


Нужна помощь: не отображается кириллица в терминале CLion. Вот так выглядит надпись
"Привет, Мир!":


  ╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А!


Вот что будет с кодировкой windows-1251:


  ╧ЁштхЄ, ╠шЁ!

    


Ответы

Ответ 1



Почему так происходит? CLion по дефолту использует UTF-8 для хранения файлов с исходным кодом. Строка "Привет, Мир!" будет представлять собой последовательность (в файле с исходником): D0 9F D1 80 D0 B8 D0 B2 D0 B5 D1 82 2C 20 D0 9C D0 B8 D1 80 21 Как видите, на 12 символов исходной строки, получили 21 байт (т.к. кириллические символы занимают больше одного байта). Компилятор GCC по умолчанию читает исходники в кодировке UTF8, если не указать другую через ключ -finput-charset. Таким образом эта последовательность байтов в неизменном виде сохранится в исполняемый файл. При запуске программы на исполнение, CLion использует стандартный cmd.exe, который по умолчанию скорей всего у вас работает в кодировке CP866. В которой наша последовательность байтов будет отображена как: ╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А! (что вы и видите в терминале CLion) Что делать? Вариант 1 Сменить кодировку файла на IBM866 (то же, что и CP866) (настройки - File Encodings) (сам файл перекодировать, если там уже был текст на русском). Теперь кириллица будет сохраняться в файле с исходным текстом в кодировке CP866 (один байт на символ), в том же виде попадать в исполняемый файл и нормально отображаться в консоли CLion. Разумеется, использовать CP866 в 17-м году, без особых на то оснований, это некультурно. Кроме того придется ограничить себя только символами из CP866. Вариант 2 Вставить в начало свой программы: system("chcp 65001"); или (потребует #include ): SetConsoleOutputCP(CP_UTF8); Консоль переключится в UTF-8, все будет отображаться как надо. Но только при использовании низкоуровневых операций вывода типа puts("Привет, Мир!");. Если выводить через std::cout, то возможен вывод типа ��ривет, Мир!. Это связано с тем, что Windows API для вывода в консоль ожидает видеть в каждом вызове законченную строку. И если оператор basic_ostream::operator<<(char*) для символа 'П' выполнит два API вызова (с D0 и 9F), то они не сольются в одну букву 'П', а будут интерпретированы и отображены как два разных символа (��). Предостережение При использовании UTF-8 в своей программе, например при хранении в std::string, следует помнить, что операции над строками могут дать не очевидные результаты (т.к. один символ теперь может занимать от 1 до 4 байтов). Кроме вывода, аналогичные проблемы ожидают и при вводе из std::cin. Таким образом, единственное прозрачное решение для Windows (даже десятки), пока остается использование латиницы.

Ответ 2



Похоже вы компилируете проект с помощью MinGW, у меня была такая же проблема с кодировками в консоли СLion (которая выводится внизу при выборе "Run" в панели инструментов справа сверху), также пробовал разные кодировки, результат один не читаемые "крякозаблики". Правда когда используешь cp-1251 и запускаешь программу в консоли Windows (CMD), то тоже выводится всё хорошо (правда это не очень удобно, надо сделать больше телодвижений). На другом ноутбуке попробовал использовать CLion вместе с CygWin и всё стало нормально при настройках кодировки по умолчанию, я использовал UTF-8.

Ответ 3



Для Clion: Cygwin - при установке в выборе пакетов нужно найти и отметить всякие cmake, GDB и прочие, кем-нибудь рекомендуемые к установке. Сlion - File - Settings - Editor - File Encodings: IDE Encoding, Project Encoding, main.cpp (Ваш исполняемый файл) - UTF-8, Default encoding for properties files - IBM866 В окне редактора внизу - UTF-8. Включить заголовочный файл Windows.h SetConsoleCP(866); SetConsoleOutputCP(866);

понедельник, 16 декабря 2019 г.

Поддержка юникода в Shiny

#кодировка #unicode #кириллица #r


В процессе создания приложения при помощи пакета Shiny столкнулся с неполной поддержкой
юникода (если это можно так назвать) для кириллических символов.
Русский текст, содержащий букву "я", вызывает ошибку

unexpected INCOMPLETE-STRING


Если текст не содержит этой буковки, то все ок.  

Файл сохраняю в юникоде, как описано в Unicode characters in Shiny apps.  

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

Пример кода:

# ui.R

shinyUI(fluidPage(
    titlePanel("Название приложения"),

    sidebarLayout(
        sidebarPanel( "sidebar panel"),
        mainPanel("main panel")
    )
))

# server.R

shinyServer(function(input, output) {
})


sessionInfo():

R version 3.2.0 (2015-04-16)
Platform: i386-w64-mingw32/i386 (32-bit)
Running under: Windows 7 (build 7601) Service Pack 1

locale:
[1] LC_COLLATE=Russian_Russia.1251  LC_CTYPE=Russian_Russia.1251   
[3] LC_MONETARY=Russian_Russia.1251 LC_NUMERIC=C                   
[5] LC_TIME=Russian_Russia.1251    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] shiny_0.11.1 zoo_1.7-12  

loaded via a namespace (and not attached):
 [1] R6_2.0.1        htmltools_0.2.6 tools_3.2.0     Rcpp_0.11.6     RJSONIO_1.3-0  
 [6] grid_3.2.0      digest_0.6.8    xtable_1.7-4    httpuv_1.3.2    mime_0.3       
[11] lattice_0.20-31

    


Ответы

Ответ 1



Почитал тут: http://anton-pribora.ru/articles/php/locales/ Немного поэкспериментировал. У меня сработало следующее: один раз в текущей сессии выполнил установку хитрой локали: Sys.setlocale("LC_ALL","Russian_Russia.20866") Все, можно запускать Shiny-приложение с буковками "я" R version 3.2.1 (2015-06-18) Platform: i386-w64-mingw32/i386 (32-bit) Running under: Windows 7 (build 7601) Service Pack 1 locale: [1] LC_COLLATE=Russian_Russia.20866 LC_CTYPE=Russian_Russia.20866 [3] LC_MONETARY=Russian_Russia.20866 LC_NUMERIC=C [5] LC_TIME=Russian_Russia.20866

воскресенье, 8 декабря 2019 г.

Кириллица в именах переменных

#кириллица #переменные


Как известно, кириллица в именах переменых это плохо. А почему? Ну, кроме известного
довода, что "а если вы будете работать с иностранными программистами?" 
P.S. Предположим, что речь идет о языке полностью поддерживающем Юникод.
    


Ответы

Ответ 1



Даже без иностранных программистов можно найти несколько относительно веских причин: Русские слова обычно длиннее английских ("получить" - "get", "страница" - "page", ну и так далее). Это, конечно, не всегда так, но в целом - соблюдается Необходимость постоянного переключения раскладки Каша из русских и английских слов визуально плохо выглядит

Ответ 2



Я лично вижу три проблемы: постоянно переключать раскладку клавиатуры. Программисты ленивые и каждый раз переключаться... А ещё какой-нибудь пунтосвитчер захочет исправлять имена переменных... появляются чудовозможности для генерации багов. Вот к примеру чем отличаются переменные int a и int а? а это с точки зрения компилятора - разные переменные. (подсказка - одна а - кириллическая). Хотя на первый взгляд это кажется бредовым, мол, недопустят такого, но по факту это всегда может случиться. Но на самом то деле это как раз и является по моему мнению, главным аргументом, почему не приживаются "интернациональные имена переменных". ну и на закуску. Как представлю себе код, в котором имена переменных написаны китайским и арабским (не забываем, что в этом языке все записывается справа налево!). А код откроют в каком то редакторе, который не полностью поддерживает юникод и часть текста отображается квадратиками. Плюс ко всему, редактирования арабской вязи - это ещё то удовольствие (настойчиво рекомендую попробовать!). Думаю, такой код будут быстро рефакторить и приводить к удобочитаемому.

Ответ 3



Кириллица - это в высшей степени патриотично. Но многие заказчики тешат себя надеждой, что код, который вы для них написали, они потом смогут продать за бугор. Или что его фирма вырастет до международных масштабов, и программисты других стран (индусы?) будут поддерживать ваш код. Так сказать, Новые Васюки станут центром вселенной. Вот поэтому нам и не дают писать расово-правильный код. ))

Ответ 4



Нет в ней ничего плохого за исключением необходимости переключать раскладку. Ну и однобуквенные переменные не надо кириллицей называть. Раньше писал так. Вот если бы нормальный свитчер был, то и сейчас бы продолжал, наверное.

Ответ 5



ключевые слова на английском if, for, function а переменные на русском. нам наоборот больше повезло, чем американцам, что мы можем так программировать. на двух языках сразу. переключение раскладки надуманная проблема, потомучто мы это делаем неосознанно, машинально, можно сделать переключение раскладки на одну кнопку, например Caps Lock то что слова длинней "получить" - "get", "страница" - "page", так они зато легко сокращаются var т = форум.пол(5, стр); русский алфавит имеет преимущество перед английским, во первых потомучто в нём 34 буквы(включая греческую z), вместо английских 24(q это k, x это ks). во вторых, крилические буквы одинаковой ширины, в отличии от английских где есть и узкие itkl и широкие wm, в русском буквы более квадратные, а слова прямоугольные, поэтому легче читаются.

воскресенье, 24 ноября 2019 г.

Русский язык в консоли


Учу C++ по книжке Страуструпа, не выводятся русские символы.
Вот код:

#include 
#include 

using namespace std;

int main()
{
    setlocale(LC_ALL, "Russian");

    string previous = " ";
    string current;

    while (cin >> current)
    {
        if (previous == current)
        {
            cout << "Повторяющееся слово: " << current << endl;
        }

        previous = current;
    }

    cin.get();
    return 0;
}


"Повторяющееся слово: " - отображается нормально благодаря setlocale.
То что после - крякозяблы, хотя повторяющееся слова находит.
setlocale пробовал разные (0, ""), "", "Rus" и пр.

В Code::Blocks всё работает и без крякозяблов. Даже без setlocale.
    


Ответы

Ответ 1



Для данной задачи существует множество решений. Если вам нужно быстрое и не обязательн универсальное решение, чтобы сильно не разбираться, прокручивайте к разделу «Менее правильные, но пригодные решения». Правильное, но сложное решение Для начала, проблема у консоли Windows состоит в том, что её шрифты, которые стоя «по умолчанию», показывают не все символы. Вам следует сменить шрифт консоли на юникодный это позволит работать даже на английской Windows. Если вы хотите поменять шрифт только для вашей программы, в её консоли нажмите на иконку в левом верхнем углу → Свойства → Шрифт. Если хотите поменять для всех будущих программ, то же самое, только заходите в Умолчания, а не Свойства. Lucida Console и Consolas справляются со всем, кроме иероглифов. Если ваши консольны шрифты позволят, вы сможете вывести и 猫, если нет, то лишь те символы, которые поддерживаются. Дальнейшее рассмотрение касается лишь Microsoft Visual Studio. Если у вас друго компилятор, пользуйтесь предложенными на свой страх и риск, никакой гарантии нету. Теперь, кодировка входных файлов компилятора. Компилятор Microsoft Visual Studi (по крайней мере, версии 2012 и 2013) компилирует исходники в однобайтных кодировка так, как будто бы они на самом деле в ANSI-кодировке, то есть для случая русской систем — CP1251. Это означает, что кодировка исходников в CP866 — неправильна. (Это важно, если вы используете L"..."-строки.) С другой стороны, если вы храните исходники в CP1251, то эти же исходники не будут нормально собираться на нерусской Windows. Поэтому стоит хранить исходники в Unicode (например, UTF-8). Настроив среду, перейдём к решению собственно задачи. Правильным решением является уйти от однобайтных кодировок, и использовать Unicod в программе. При этом вы получите правильный вывод не только кириллицы, но и поддержк всех языков (изображение отсутствующих в шрифтах символов будет отсутствовать, но вы сможете с ними работать). Для Windows это означает переход с узких строк (char*, std::string) на широкие (wchar_t*, std::wstring), и использование кодировки UTF-16 для строк. (Ещё одна проблема, которую решает использование широких строк: узкие строки пр компиляции кодируются в однобайтную кодировку используя текущую системную кодовую страницу, то есть, ANSI-кодировку. Если вы компилируете вашу программу на английской Windows, это приведёт к очевидным проблемам.) Вам нужно _setmode(_fileno(...), _O_U16TEXT); для переключения режима консоли: #include #include #include int wmain(int argc, wchar_t* argv[]) { _setmode(_fileno(stdout), _O_U16TEXT); _setmode(_fileno(stdin), _O_U16TEXT); _setmode(_fileno(stderr), _O_U16TEXT); std::wcout << L"Unicode -- English -- Русский -- Ελληνικά -- Español." << std::endl; // или wprintf(L"%s", L"Unicode -- English -- Русский -- Ελληνικά -- Español.\n"); return 0; } Такой способ должен работать правильно с вводом и выводом, с именами файлов и перенаправлением потоков. Важное замечание: потоки ввода-вывода находятся либо в «широком», либо в «узком состоянии — то есть, в них выводится либо только char*, либо только wchar_t*. После первого вывода переключение не всегда возможно. Поэтому такой код: cout << 5; // или printf("%d", 5); wcout << L"привет"; // или wprintf(L"%s", L"привет"); вполне может не сработать. Используйте только wprintf/wcout. Если очень не хочется переходить на Unicode, и использовать однобайтную кодировку будут возникать проблемы. Для начала, символы, не входящие в выбранную кодировку (например для случая CP1251 — базовый английский и кириллица), работать не будут, вместо них буде вводиться и выводиться абракадабра. Кроме того, узкие строковые константы имеют ANSI-кодировку, а это значит, что кириллические строковые литералы на нерусской системе не сработают (в них будет зависимая от системной локали абракадабра). Держа в голове эти проблемы, переходим к изложению следующей серии решений. Менее правильные, но пригодные решения В любом случае, поставьте юникодный шрифт в консоли. (Это первый абзац «сложного» решения.) Убедитесь, что ваши исходники в кодировке CP 1251 (это не само собой разумеется особенно если у вас не русская локаль Windows). Если при добавлении русских букв и сохранении Visual Studio ругается на то, что не может сохранить символы в нужной кодировке, выбирайте CP 1251. (1) Если компьютер ваш, вы можете поменять кодовую страницу консольных программ на вашей системе. Для этого сделайте вот что: Запустите Regedit. На всякий пожарный экспортируйте куда-нибудь реестр (этот шаг все почему-то пропускают, так что когда всё сломается, мы вас предупреждали). В разделе HKEY_CURRENT_USER\Console найдите ключ CodePage (если нету, создайте ключ с таким названием и типом DWORD). Установите значение по ключу (левая клавиша/изменить/Система счисления = десятичная) на 1251. Не забудьте перегрузиться после изменений в реестре. Преимущества способа: примеры из книг начнут работать «из коробки». Недостатки: смен реестра может повлечь за собой проблемы, кодировка консоли меняется глобально и перманентн — это может повлиять сломать другие программы. Плюс эффект будет только на вашем компьютере (и на других, у которых та же кодировка консоли). Плюс общие проблемы неюникодных способов. Примечание. Установка глобальной кодовой страницы консоли через параметр реестр HKEY_CURRENT_USER\Console\CodePage не работает в Windows 10, вместо него будет использован кодовая страница OEM - предположительно баг в conhost. При этом установка кодовой страницы консоли на уровне конкретного приложения (HKEY_CURRENT_USER\Console\(путь к приложению)\CodePage) работает. (2) Вы можете поменять кодировку только вашей программы. Для этого нужно сменит кодировку консоли программным путём. Из вежливости к другим программам не забудьте потом вернуть кодировку на место! Это делается либо при помощи вызова функций SetConsoleCP(1251); SetConsoleOutputCP(1251); в начале программы, либо про помощи вызова внешней утилиты system("chcp 1251"); (То есть, у вас должно получиться что-то вроде #include int main(int argc, char* argv[]) { std::system("chcp 1251"); ... или #include int main(int argc, char* argv[]) { SetConsoleCP(1251); SetConsoleOutputCP(1251); ... и дальше обыкновенный код программы.) Можно обернуть эти вызовы в класс, чтобы воспользоваться плюшками автоматического управления временем жизни объектов C++. Пример: #include #include int chcp(unsigned codepage) { // составить команду из кусочков std::string command("chcp "); command += codepage; // выполняем команду и возвращаем результат return !std::system(command.c_str()); } // этот код будет запущен перед main static int codepage_is_set = chcp(1251); (если выполняете задание из Страуструпа можно вставить в конец заголовочного файла std_lib_facilities.h) Или так: #include class ConsoleCP { int oldin; int oldout; public: ConsoleCP(int cp) { oldin = GetConsoleCP(); oldout = GetConsoleOutputCP(); SetConsoleCP(cp); SetConsoleOutputCP(cp); } // поскольку мы изменили свойства внешнего объекта — консоли, нам нужно // вернуть всё как было (если программа вылетит, пользователю не повезло) ~ConsoleCP() { SetConsoleCP(oldin); SetConsoleOutputCP(oldout); } }; // и в программе: int main(int argc, char* argv[]) { ConsoleCP cp(1251); std::cout << "русский текст" << std::endl; return 0; } Если вам нужен не русский, а какой нибудь другой язык, просто замените 1251 на идентификато нужной кодировки (список указан ниже в файле), но, разумеется, работоспособность не гарантируется. Остались методы, которые тоже часто встречаются, приведём их для полноты. Методы, которые работают плохо (но могут помочь вам) Метод, который часто рекомендуют — использование конструкции setlocale(LC_ALL, "Russian") У этого варианта (по крайней мере в Visual Studio 2012) гора проблем. Во-первых, проблем с вводом русского текста: введённый текст передаётся в программу неправильно! Нерусский текст (например, греческий) при этом вовсе не вводится с консоли. Ну и общие для всех неюникодных решений проблемы. Ещё один метод, не использующий Unicode — использование функций CharToOem и OemToChar Этот метод требует перекодировки каждой из строк при выводе, и (кажется) слабо поддаётс автоматизации. Он также страдает от общих для неюникодных решений недостатков. Кром того, этот метод не будет работать (не только с константами, но и с runtime-строками!) на нерусской Windows, т. к. там OEM-кодировка не будет совпадать с CP866. В дополнение можно так же сказать что эти функции поставляются не со всеми версиями Visual Studio — например в некоторых версиях VS Express их просто нет. Источники: Как выводить на экран и вводить данные типа wchar_t[]? к сожалению, автор того вопроса пользовался компилятором MinGW под Cygwin и WinXP, что делает большинство современных решений неприменимыми. Output unicode strings in Windows console app Conventional wisdom is retarded, aka What the @#%&* is _O_U16TEXT? What's the difference between printf(“%s”), printf(“%ls”), wprintf(“%s”), and wprintf(“%ls”)? Русский язык в исходном коде в Dev C++ Code Page Identifiers

Ответ 2



Поэтому стоит хранить исходники в Unicode (например, UTF-8). Причем сохранить следует с сигнатурой Ситуацию частично спасает пересохранение исходников в кодировке UTF-8 с обязательны символом BOM, без него Visual Studio начинает интерпретировать «широкие» строки с кириллице весьма своеобразно. Однако, указав BOM (Byte Order Mark — метка порядка байтов) кодировки UTF-8 — символ, кодируемый тремя байтами 0xEF, 0xBB и 0xBF, мы получаем узнавание кодировки UTF-8 в любой системе Пишем по-русски в коде

Ответ 3



Для Clion: Cygwin - при установке в выборе пакетов нужно найти и отметить всякие cmake, GD и прочие, кем-нибудь рекомендуемые к установке. Сlion - File - Settings - Editor - File Encodings: IDE Encoding, Project Encoding, main.cpp (Ваш исполняемый файл) - UTF-8, Default encoding for properties files - IBM866 В окне редактора внизу - UTF-8. Включить в проект заголовочный файл Windows.h SetConsoleCP(866); SetConsoleOutputCP(866);

Ответ 4



Стоит пояснить кое-что для тех, кто ищет правильный ответ по поводу функции setlocale: Метод, который часто рекомендуют — использование конструкции setlocale(LC_ALL "Russian"); У этого варианта (по крайней мере в Visual Studio 2012) гора проблем. Во-первых проблема с вводом русского текста: введённый текст передаётся в программу неправильно! Нерусский текст (например, греческий) при этом вовсе не вводится с консоли. Ну и общие для всех неюникодных решений проблемы. Я добавлю по этому методу побольше информации: Его вообще не правильно рекомендуют! Начнём с первого: Во втором параметре функция принимает не название страны или языка хотя в некоторых случаях она сработает, а языковый идентификатор, согласно ISO 3166-1. Поэтому правильно и корректно указывать: "ru-RU". Теперь второе: в документации к этой функции написано чёрным по белому: "If executio is allowed to continue, the function sets errno to EINVAL and returns NULL." Что буквально толкуется: при возникновении ошибки, функция устанавливает значение переменной errno в EINVAL и возвращает NULL. В случае возникновения ошибки, errno всегда будет равен EINVAL, что означает: н верный аргумент. Поэтому её проверять нет смысла, а вот исполнение функции должно быть проверено. Поэтому правильный вызов функции setlocale выглядит следующим образом: if (setlocale(LC_ALL, "ru-RU") == NULL) { cout << "Error set locale ru-RU." << endl; return -1; // или принудительно ставим таблицу 1251 через SetConsoleCP. // выше пример есть. И не забываем проверять результат SetConsoleCP // Если ошибка возникла, то код ошибки смотрим через GetLastError. } И не забывайте, что setlocale устанавливает локальную таблицу только для ANSI кодировки, поэтому и не будут отображаться греческие, испанские, китайские и даже японские знаки. Для русского языка это будет таблица номер 1251. И важно: почему эта функция является надёжней, нежели прямая установка таблицы символо через SetConsoleCP, ибо потому, что она переключает все внутренние надстройки именно для раскладки под язык. Начиная от стандарта отображения даты, заканчивая знаками разделителя. И да, не стоит устанавливать языковый указатель виде "ru", так как в зависимост от сборки самой ось и имеющихся языковых пакетов, может установиться ru-BY, ru-UA, ru-M и другие языковые стандарты, значительно отличающиеся от ru-RU. И категорично нельз указывать "Russia", "Russian", "Russian Federation" (да, такую вакханалию уже встречал пару раз). Хотя функция производит проверку и по названию региона, не всегда в таблице локализации это указано, или может быть указано "Россия" или "Русский" уже на нашей раскладке. Это и есть основная ошибка, из-за которой функция setlocale зачастую отказывается работать. И да, для приложения, работающего в режиме юникогда, стоит использовать функцию _wsetlocale Она идентична, и также устанавливает базовые настройки для локализации. Кроме того если проект приложения в Visual Studio настроен в режим юникода, то и будет работать только _wsetlocale, так как setlocale, по документации, не приспособлена к работе с юникодом вообще никак. UPD. Совсем забыл указать, что функция setlocale и _wsetlocale, в случае успеха вернёт именно идентификатор региона. То есть, в нашем случае строку "ru_RU\0".

суббота, 13 июля 2019 г.

Универсальное решение проблем с кириллицей C++

Веду разработку на операционной системе macOS. Возникают кучи проблем с кириллицей (string или char*), например, при работе с функциями regex, ::tolower/::toupper и тд.
При запросе locale в терминале, имею следующее:
LANG="ru_RU.UTF-8" LC_COLLATE="ru_RU.UTF-8" LC_CTYPE="ru_RU.UTF-8" LC_MESSAGES="ru_RU.UTF-8" LC_MONETARY="ru_RU.UTF-8" LC_NUMERIC="ru_RU.UTF-8" LC_TIME="ru_RU.UTF-8" LC_ALL=
Использую C++11. Boost принципиально использовать не хочу и, желательно, чтобы решение могло быть перенесено в будущем на линкус (отсылка к непереносимому codecvt).
Собственно сам вопрос: как можно исправить проблему кириллицы во всей программе? Например, использовать грамотно locale.h (и как это - грамотно?) или что-нибудь еще.
UPD:
Вывод текста я осуществляю непосредственно в консоль. В консоль вывод происходит отлично, вот только преобразования через transform, используя параметры ::tolower, ::toupper успешно игнорируются. Используя codecvt я смог получить из string -> wstring, выполнил ::tolower и смог так же сделать wstring->string, однако, это явный "костыль" и использовать его всегда, когда мне надо что-то сделать с байтами строки - не выход.
Если я вывожу русский текст в ncurses, получается так: (Я какой-то текст) "Я какой-?~Bо ?~Bек?~A?~B"


Ответ

Очень понимаю ваше желание не использовать Boost(тоже такой принцип).
Что бы раз и навсегда забыть о проблемах с кодировкой лучше всего использовать utf8 и в STL есть его реализация wstring
wstring str = u8"кириллический текст";//u8 преобразует ansi символы в utf8.
Используя wstring о проблемах с локалью можно забыть.
Из плюсов это переносимость на всё что угодно, а из минусов это повышенное потребление памяти(не смертельно но всё же).
И, кстати говоря, считается правилом хорошего тона не использовать std::wcout и std::cout (равно как и пару std::wcin и std::cin) в пределах одного приложения(есть проблемы их совместного использования).

воскресенье, 7 июля 2019 г.

При запуске subprocess команды с кириллицей происходит ошибка: UnicodeEncodeError: 'ascii' codec can't encode

# -*- coding: utf-8 -*- from __future__ import unicode_literals import argparse import ctypes import subprocess parser = argparse.ArgumentParser(description='test') parser.add_argument('-f', help = 'folder') args = parser.parse_args() path = args.f if ctypes.windll.shell32.IsUserAnAdmin() != 0: print 'You admin
' output = subprocess.check_output(['takeown', '/F', path, '/R', '/A']) print output output2 = subprocess.check_output(['icacls', path, '/grant:r', 'Администраторы:F']) print output2 else: print 'You not admin' exit(0)
Как отобразить? "Администраторы"


Ответ

Почему UnicodeEncodeError при вызове subprocess.check_output()
Traceback показывает, что subproces.check_output() вызывает subprocess.Popen, которая на Windows вызывает _subprocess.CreateProcess на Питоне 2
Благодаря from __future__ import unicode_literals директиве: 'abc' у вас имеет unicode тип (Python 2).
sp_CreateProcess преобразует unicode аргумент в байты (char*), используя 'z' формат, который использует кодировку по умолчанию (sys.getdefaultencoding() == 'ascii' на Питоне 2). См. Parsing arguments and building values
Так как используется CreateProcessA() WinAPI (не Unicode) на Windows в Питоне 2, то перед передачей в subprocess, руками попробуйте закодировать не-ascii аргументы, используя ANSI codepage:
args = [u'icacls', path, u'/grant:r', u'Администраторы:F'] args = [arg.encode(sys.getfilesystemencoding()) for arg in args] subprocess.check_call(args)
Почему кракозябры в traceback
На Питоне 2, 'abc' строковая константа (string literal) это последовательность байт, представляющая символы, записанные в исходном коде, в кодировке, указанной наверху файла (# -*- coding: utf-8 -*- -- PEP 263 encoding declaration). from __future__ import unicode_literals директива превращает 'abc' (байты) в u'abc' (unicode).
Кракозябры могут появиться, когда текст, закодированный в одной кодировке, показывается используя другую (несовместимую) кодировку:
>>> print(u'Администраторы:F'.encode('utf-8').decode('cp866')) ╨Р╨┤╨╝╨╕╨╜╨╕╤Б╤В╤А╨░╤В╨╛╤А╤Л:F
Исходный код (utf-8) как байты напрямую без перекодировки выводится в консоль (cp866 здесь), поэтому вы видите кракозябры -- это можно считать багом в Питоне 2.

понедельник, 10 июня 2019 г.

Не отображаются кириллические символы в терминале Debian у программ на Java скомпилированных в Win10

Собственно установил я себе недавно Debian 9, не смотря на то что в линуксе новичек проблем особых не было. Установил себе jdk 8 от Oracle решил проверить работоспособность и получил странный результат, те файлы которые я создал и скомпелировал в линуксе отображают кирилицу в консоле без проблем.
Файлы же скомпилированные в Win10 показывают всякую ерунду. Хотя сама консоль настроена и работает верно, локаль и utf 8 итд.
И в win10 и debian создавал файлы в sublime text 3.
В чем может быть проблема?
PS: В java и debian новичек так что это может быть стандартная ошибка.

Извиняюсь что не получилось ответить сразу, да это скорей всего из-за кодировки. Но из-за какой именно кодировки я так и не понял.
Провел небольшой тест: Создал три файла, все три сделал в SublimeText3 и сохранил с кодировкой UTF-8. Вот что было внутри.
class Test_Win10_Default { public static void main(String[] args) { System.out.println("ABCabc"); System.out.println("АБВабв"); System.out.println("àéèç"); } }
Первый файл скомпилировал в командной строке WIN10, второй файл был скомпилирован там-же в командной строке, но перед этим я написал команду chcp 65001 поменяв кодировку командной строки на UTF-8. Результат такой, оба файла отображали символы корректно толь после того как я менял кодировку, при это закрывая командную строку кодировка не сохранялась и приходилось опять вводить команду на её смену.
Далее, я перешел в Debian и создал файл с точно таким же кодом, там всё работало нормально. Файлы созданные в Виндовс не работали, оба. Перейдя же обратно в Виндовс я обнаружил что третий файл созданный в Линукс не работает в Виндовс. Даже после смены кодировки терминал отображал первые две строки, а вот третью с французскими буквами, он не понимал.
В общем я запутался в конец. Неужели нет способа поставить одну кодировку Юникод в обеих системах чтобы больше не думать о таких вещах?


Ответ

По умолчанию компилятор использует системную кодировку. В Windows это cp1251. Поэтому собранные под Windows классы показывают крякозяблы. Чтобы этого избежать, необходимо явно указать компилятору какую кодировку использовать
javac -encoding utf-8 Test_Win10_Default.java
Впрочем, вывести символ à в консоль cmd вам это всё равно не поможет. Ничто не поможет нормально выводить двухбайтовую кодировку в консоль заточенную под использование однобайтовой cp866.

пятница, 7 июня 2019 г.

Почему добавляются непонятные символы в БД при вводе русских букв (кириллицы) в phpMyAdmin?

На странице, в которой ввожу данные, кодировка текста "< meta charset="utf-8>". Ввел строку "Главная"

Вывод на другой странице выглядит так:

В БД кодировка - utf8_general_ci, а запись этих строк выглядит вот так:


Ответ

Скрипт, который пишет в БД, не установлена кодировка обмена с mysql. В итоге скрипт пишет в БД в кодировке по умолчанию (скорее всего Latin). Поскольку и читает он в этой же кодировке, то на сайте все отображается как надо, а вот в phpMyAdmin, настроенном на utf8, вы видите "кракозябры".
В скрипте, после соединения с БД надо выполнить запрос
SET NAMES utf8
чтобы установить нужную кодировку обмена с БД

пятница, 1 марта 2019 г.

Почему метод onEditorAction не отлавливает нажатие Enter на программной клавиатуре при включенной русской раскладке, но отлавливает его на английской?

Прочитал на этом сайте и на его английском прародителе много схожих вопросов и ответов, перепробовал разные условия if, но так и не понял, почему в английской раскладке все работает так, как я и ожидаю, тогда как в русской - нажатие enter просто переводит в новую строку (неужели код нажатия клавиши зависит от раскладки?). У EditText задан атрибут inputType="textMultiLine".
public boolean onEditorAction(TextView textView, int actionId, KeyEvent event) {
if (event != null) {
if ((event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) { // сохраняем текст, введенный до нажатия Enter в переменную currentMessage = editText.getText().toString(); editText.setText(""); return true; }
} return false; }
Пробовал менять KeyEvent.ACTION_DOWN на actionId == EditorInfo.IME_ACTION_SEND с предварительным editText.setImeActionLabel("SEND", EditorInfo.IME_ACTION_SEND);, но это не помогло. Заранее благодарю за ответ.


Ответ

Java
editText.setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { boolean handled = false; if (actionId == EditorInfo.IME_ACTION_SEND) {
currentMessege = editText.getText().toString(); setText(currentMessege); editText.setText("");
handled = true; } return handled; } });
XML

Вместо textMultiLine Используйте android:inputType="textImeMultiLine" - проверил лично, работает на все 100% при русской и английской раскладке.

Документация
P.S. Вкратце, "Enter" на клавиатуре - это imeOptions (Specify the Input Method Action), существуют:
IME_ACTION_SEND (картинка письмо) IME_ACTION_DONE (галочка) IME_ACTION_SEARCH (лупа)
и т.д
в Java нужно обозначать .IME_ACTION_*, в xml android:imeOptions="action*"

среда, 12 декабря 2018 г.

Sqlite игнорировать регистр в условии WHERE

Подскажите как на андроиде в sqlite базе сделать выборку на кирилице, игнорируя регистр? запросы с LIKE, COLLATE NOCASE и UPPER(column_name) работают только для английских букв! А для русских нет! Для примера, имею таблицу favourite с записью title = Тест, юзер пытается запросить её но в поле поиска вводит слово тест маленькими буквами. пробовал такие варианты: SELECT * FROM favourite WHERE title LIKE '%тест%' SELECT * FROM favourite WHERE UPPER(title) LIKE UPPER('%тест%') SELECT * FROM favourite WHERE title LIKE '%ТЕСТ%' COLLATE NOCASE все три варианта не подходят, больше ничего не нагуглил. Подскажите пожалуйста решение ps: запросы осуществляю так: SQLiteDatabase db = getWritableDatabase(); //*extends SQLiteOpenHelper* Cursor cursor = db.rawQuery(sql, null);


Ответ

Вообще-то это известный баг или фича (кому как) SQLite. Он не понимает case-insensitive where/like/glob, когда символы не в ASCII. Как говорит мануал: A bug: SQLite only understands upper/lower case for ASCII characters by default. The LIKE operator is case sensitive by default for unicode characters that are beyond the ASCII range. For example, the expression 'a' LIKE 'A' is TRUE but 'æ' LIKE 'Æ' is FALSE.) Единственный способ обойти это ограничение, это завести хранимую процедуру выполняющую операцию сравнения. Update Я слегка погорячился по поводу хранимых процедур в SQLite. SQLite не поддерживает хранимые процедуры в общепринятом смысле, нужно писать т.н. custom function на С, пример здесь

среда, 31 октября 2018 г.

Отображение кириллицы в CLion

Нужна помощь: не отображается кириллица в терминале CLion. Вот так выглядит надпись "Привет, Мир!":
╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А!
Вот что будет с кодировкой windows-1251
╧ЁштхЄ, ╠шЁ!


Ответ

Почему так происходит?
CLion по дефолту использует UTF-8 для хранения файлов с исходным кодом. Строка "Привет, Мир!" будет представлять собой последовательность (в файле с исходником):
D0 9F D1 80 D0 B8 D0 B2 D0 B5 D1 82 2C 20 D0 9C D0 B8 D1 80 21
Как видите, на 12 символов исходной строки, получили 21 байт (т.к. кириллические символы занимают больше одного байта).
Компилятор GCC по умолчанию читает исходники в кодировке UTF8, если не указать другую через ключ -finput-charset. Таким образом эта последовательность байтов в неизменном виде сохранится в исполняемый файл.
При запуске программы на исполнение, CLion использует стандартный cmd.exe, который по умолчанию скорей всего у вас работает в кодировке CP866. В которой наша последовательность байтов будет отображена как:
╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А!
(что вы и видите в терминале CLion)

Что делать?
Вариант 1
Сменить кодировку файла на IBM866 (то же, что и CP866) (настройки - File Encodings) (сам файл перекодировать, если там уже был текст на русском). Теперь кириллица будет сохраняться в файле с исходным текстом в кодировке CP866 (один байт на символ), в том же виде попадать в исполняемый файл и нормально отображаться в консоли CLion. Разумеется, использовать CP866 в 17-м году, без особых на то оснований, это некультурно. Кроме того придется ограничить себя только символами из CP866
Вариант 2
Вставить в начало свой программы:
system("chcp 65001");
или (потребует #include ):
SetConsoleOutputCP(CP_UTF8);
Консоль переключится в UTF-8, все будет отображаться как надо. Но только при использовании низкоуровневых операций вывода типа puts("Привет, Мир!");. Если выводить через std::cout, то возможен вывод типа ��ривет, Мир!. Это связано с тем, что Windows API для вывода в консоль ожидает видеть в каждом вызове законченную строку. И если оператор basic_ostream::operator<<(char*) для символа 'П' выполнит два API вызова (с D0 и 9F), то они не сольются в одну букву 'П', а будут интерпретированы и отображены как два разных символа (��).

Предостережение
При использовании UTF-8 в своей программе, например при хранении в std::string, следует помнить, что операции над строками могут дать не очевидные результаты (т.к. один символ теперь может занимать от 1 до 4 байтов).
Кроме вывода, аналогичные проблемы ожидают и при вводе из std::cin. Таким образом, единственное прозрачное решение для Windows (даже десятки), пока остается использование латиницы.

суббота, 27 октября 2018 г.

Поддержка юникода в Shiny

В процессе создания приложения при помощи пакета Shiny столкнулся с неполной поддержкой юникода (если это можно так назвать) для кириллических символов. Русский текст, содержащий букву "я", вызывает ошибку
unexpected INCOMPLETE-STRING
Если текст не содержит этой буковки, то все ок.
Файл сохраняю в юникоде, как описано в Unicode characters in Shiny apps.
Пока что пишу эскейп-код \u044f вместо буквы, но хотелось бы разобраться в причинах такого поведения и, возможно, решить эту проблему без используемого сейчас костыля.
Пример кода:
# ui.R
shinyUI(fluidPage( titlePanel("Название приложения"),
sidebarLayout( sidebarPanel( "sidebar panel"), mainPanel("main panel") ) ))
# server.R
shinyServer(function(input, output) { })
sessionInfo():
R version 3.2.0 (2015-04-16) Platform: i386-w64-mingw32/i386 (32-bit) Running under: Windows 7 (build 7601) Service Pack 1
locale: [1] LC_COLLATE=Russian_Russia.1251 LC_CTYPE=Russian_Russia.1251 [3] LC_MONETARY=Russian_Russia.1251 LC_NUMERIC=C [5] LC_TIME=Russian_Russia.1251
attached base packages: [1] stats graphics grDevices utils datasets methods base
other attached packages: [1] shiny_0.11.1 zoo_1.7-12
loaded via a namespace (and not attached): [1] R6_2.0.1 htmltools_0.2.6 tools_3.2.0 Rcpp_0.11.6 RJSONIO_1.3-0 [6] grid_3.2.0 digest_0.6.8 xtable_1.7-4 httpuv_1.3.2 mime_0.3 [11] lattice_0.20-31


Ответ

Почитал тут: http://anton-pribora.ru/articles/php/locales/
Немного поэкспериментировал.
У меня сработало следующее: один раз в текущей сессии выполнил установку хитрой локали:
Sys.setlocale("LC_ALL","Russian_Russia.20866")
Все, можно запускать Shiny-приложение с буковками "я"
R version 3.2.1 (2015-06-18) Platform: i386-w64-mingw32/i386 (32-bit) Running under: Windows 7 (build 7601) Service Pack 1
locale: [1] LC_COLLATE=Russian_Russia.20866 LC_CTYPE=Russian_Russia.20866 [3] LC_MONETARY=Russian_Russia.20866 LC_NUMERIC=C [5] LC_TIME=Russian_Russia.20866

вторник, 9 октября 2018 г.

Кириллица в именах переменных

Как известно, кириллица в именах переменых это плохо. А почему? Ну, кроме известного довода, что "а если вы будете работать с иностранными программистами?" P.S. Предположим, что речь идет о языке полностью поддерживающем Юникод.


Ответ

Даже без иностранных программистов можно найти несколько относительно веских причин: Русские слова обычно длиннее английских ("получить" - "get", "страница" - "page", ну и так далее). Это, конечно, не всегда так, но в целом - соблюдается Необходимость постоянного переключения раскладки Каша из русских и английских слов визуально плохо выглядит