LINUX.ORG.RU

Вывод русских символов в консоль.(с++)

 


0

2

Есть строка с русскими буквами и ее необходимо вывести посимвольно. При выводе символов вместо букв получаю - �. НО если вывести строку целиком, то все символы отображаются правильно! Пробовал выставить локаль, но ничего не изменилось. Как вывести русские буквы на консоль?


Ответ на: комментарий от madao

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

anonymous
()
Ответ на: комментарий от madao

Потому что байты в значки интерпретирует терминал, если ты полностью выдал строку, то он всю информацию получил, а если ты по байтам рвёшь и перемежаешь LF, то и получаются некорректные кодовые точки.

Artificial_Thought ★★★★
()
Ответ на: комментарий от Artificial_Thought

Скачал библиотеку и вот что вышло

#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <iostream>

int main(int argc, char **argv)
{
	UnicodeString s("привет");
	std::cout<<(s[0]);
	return 0;
}
Вывод код символа, но не символ.

madao
() автор топика
Ответ на: комментарий от madao

В Линупсе принято использовать UTF-8 для строк. Берёте строку как char*, берёте <unicode/utf8.h>, U8_FWD_1 позволяет перейти к следующей code point. С помощью неё можно найти в строке границы отдельных UTF-8-символов и вывести их на терминал, перемежая пробелами или чем там надо.

ilammy ★★★
()

Раз и навсегда понять, что такое локальных и кодировка. По-другому никак.

chg ★★★★★
()
Ответ на: комментарий от madao

Что бы вывести символ пришлось сделать такой финт

#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <iostream>

int main(int argc, char **argv)
{
	icu::UnicodeString s("привет");
	icu::UnicodeString ss(s[0]);
	std::cout<<ss;
	return 0;
}
Если кто то знает вариант получше прошу поделиться. Всем помогавшим спасибо!

madao
() автор топика
Ответ на: комментарий от madao

Если кто то знает вариант получше прошу поделиться. Всем помогавшим спасибо!

#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <iostream>

using namespace std;

int main(int argc, char **argv)
{
	char *text = "привет";
	icu::UnicodeString s(text);
	cout << "Text bytes count: " << string(text).size() << endl;
	cout << "Text symbols count: " << s.length() << endl;
	icu::UnicodeString first_symbol(s.charAt(0));
	cout << "First symbol: " << first_symbol << endl;
	return 0;
}

Иди почитай на википедии про utf8 и тогда поймешь что не всегда количество байт равняется количеству символов.

V1KT0P ★★
()

Почитайте о мультибайтовых кодировках, это решит вашу проблему.
Тот же utf-8 - это от одного до шести байт на символ. Нет ничего удивительного, что вы получаете мусор при выводе одного байта.

andreyu ★★★★★
()
Ответ на: комментарий от Adonai

Она достаточно компактная (оставляет за рамками некоторые вопросы i18n). Текст — сложная вещь.

x3al ★★★★★
()
Ответ на: комментарий от Adonai

Там ЕМНИП лежат ресурсы примеров текста в различных кодировках, чтобы кодировку автоопределять.

vurdalak ★★★★★
()
Ответ на: комментарий от madao

Правило такое:

  • внутри себя Вы всё можете делать в wchar_t.
    Естественно, для сколько-нибудь сложной обработки текста это заметно удобнее чем возиться с мультибайтными последовательностями неизвестной заранее длины.
  • При выпихивании результатов в байт-ориентированные потоки результат лучше переводить из символов в последовательности байтов.

В принципе, есть fputwc, но там нужно быть достаточно осторожным, так как нельзя бездумно мешать в рамках одного потока байтовый и wchar'овый вывод. Читать info (libc) Streams and I18N

AlexM ★★★★★
()
Последнее исправление: AlexM (всего исправлений: 1)
Ответ на: комментарий от AlexM

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

alex@galene ~ $ cat >/tmp/hello.c 
#include <wchar.h>
#include <stdio.h>
#include <locale.h>

int main(void) {
  setlocale(LC_CTYPE, "");
  wchar_t greetings[] = L"Привет, мир!\n";
  for(wchar_t* p = greetings; *p; ++p) {
    if (*p == L'и')
      *p = L'Ю';
    fputwc(*p, stdout);
  }
  return 0;
}
alex@galene ~ $ cc -Wall -std=c99 -o /tmp/hello /tmp/hello.c
alex@galene ~ $ /tmp/hello                              
ПрЮвет, мЮр!
alex@galene ~ $ _

Но нужно отчётливо понимать, что этим методом Вы сможете писать в консоль надписи только в текущей локали, что бывает далеко не всегда удобно. Для более сложного вывода, да, перед выводом нужно использовать явную конвертацию в требуемую кодировку. <вброс>Возможно, стоит сразу посмотреть в сторону Qt ;-P</вброс>, там отделение внутреннего представления строк от транспортного уровня сделано очень по-человечески.

AlexM ★★★★★
()
Последнее исправление: AlexM (всего исправлений: 3)
Ответ на: комментарий от andreyu

Вне стандарта. В винде 16 бит, в линуксе 32 бита.

можно и в стандарте

в этом:

           _XOPEN_SOURCE >= 500 || _ISOC99_SOURCE ||
           _ISOC95_SOURCE /* Since glibc 2.12 */ ||
           _POSIX_C_SOURCE >= 200112L;
           or cc -std=c99

man 3 wprintf

emulek
()
Ответ на: комментарий от Adonai

Господа, почему библиотека ICU такая жирная?

шаблоны все такие жирные и компилляться долго. Смирись.

emulek
()

Пробовал выставить локаль, но ничего не изменилось. Как вывести русские буквы на консоль?

Hello Masha.

Local postav utf-8. Chto ti takaya bestolkovka?

anonymous
()
Ответ на: комментарий от emulek

Это не стандарт. ISO/IEC 10646:2003 — стандарт. А wchar_t на *bsd запросто может быть восьмибитным (в зависимости от локали).

x3al ★★★★★
()
Ответ на: комментарий от x3al

А wchar_t на *bsd запросто может быть восьмибитным (в зависимости от локали).

Тонко подосрал BSD?)

Pavval ★★★★★
()
Ответ на: комментарий от x3al

Это не стандарт.

это список стандартов.

wchar_t на *bsd запросто может быть восьмибитным (в зависимости от локали).

это конечно доказывает, что wchar_t ни в каких стандартах нет, и быть не может...

emulek
()
Ответ на: комментарий от emulek

Эмм. В твоих «стандартах» гарантируется, что wchar_t будет с glibc (поэтому ты ссылаешься на man 3 вместо man 3p), но не гарантируется, что оно будет юзабельно (8битное в зависимости от локали там, где glibc может и не быть). Никем не гарантируется, что wchar_t юникодно.

Зачем оно такое?

Есть char16_t и char32_t, которые переносимы.

x3al ★★★★★
()
Ответ на: комментарий от emulek

И да, твой же man 3 wprintf:

The glibc represents wide characters using their Unicode (ISO-10646) code point, but other platforms don't do this.

x3al ★★★★★
()
Ответ на: комментарий от x3al

Есть char16_t и char32_t, которые переносимы.

ИМХО лучше использовать обычный char, и не забивать голову, если требуется переносимость. Т.е. mbtowc(3), или что там у вас в *bsd.

А когда переносимость НЕ требуется, то юзать wchar_t и не забивать мозг переносимостью.

emulek
()
Ответ на: комментарий от emulek

Если хочется НЕ забивать голову, то безотносительно переносимости НУЖНО использовать char. Без mbtowc. Не прикасаться к wide character'ам своими грязными руками хотя бы потому, что они не нужны и работать с ними СЛОЖНО даже без учёта портабельности. Главное — не забыть о setlocale и не пытаться делать вид, что символ == char.

mbtowc и компания нужны в одном случае: когда хочется работать только под линуксом, осознавая локали (т.е. делая дополнительную ручную работу) и получая возможность хоть как-то работать с юникодом при неюникодной локали. В противном случае работаем со строкой как с потоком в мультибайтной кодировке без преобразования в wchar. Нужных библиотек полно.

Кстати, можешь сказать, зачем тебе в последний раз понадобилось посимвольно смотреть на строку? Или использовать длину строки в wchar'ах (что практически на 100% гарантирует, что твоя софтина не умеет в юникод, хоть и старается)?

x3al ★★★★★
()
Ответ на: комментарий от x3al

Кстати, можешь сказать, зачем тебе в последний раз понадобилось посимвольно смотреть на строку?

как узнать, что «корова» очень похоже на «карова», а вот на «свинья» не похоже? А «ккрова» — вообще что-то неведомое. см. здесь http://ru.wikipedia.org/wiki/Расстояние_Левенштейна

emulek
()
Ответ на: комментарий от x3al

Не прикасаться к wide character'ам своими грязными руками хотя бы потому, что они не нужны и работать с ними СЛОЖНО даже без учёта портабельности

да не то-что «сложно», просто НЕ НУЖНО. Т.ч в целом — согласен.

emulek
()
Ответ на: комментарий от emulek

Для этого нужно не wchar_t, а честный глиф. Вычленять глиф из строки — нетривиально как в случае с char* с utf-8, так и с wchar_t* c utf-32 нативной endianness.

x3al ★★★★★
()
Ответ на: комментарий от x3al

Хотя можно проитерировать char* любым юникодным костылём (хотя бы g_utf8_next_char если нет фантазии) и считать за символы только alnum. После приведения к каноничной форме, конечно.

x3al ★★★★★
()
Ответ на: комментарий от x3al

Для этого нужно не wchar_t, а честный глиф. Вычленять глиф из строки — нетривиально как в случае с char* с utf-8, так и с wchar_t* c utf-32 нативной endianness.

зачем мне твои глифы вычленять? Просто СИМВОЛЫ.

Хотя можно проитерировать char* любым юникодным костылём

можно. Но дольше.

emulek
()
Ответ на: комментарий от emulek

Просто СИМВОЛ может оказаться знаком ударения, нулевым пробелом, нулевым неразделителем, мягким переносом, комбинирующим умлаутом (если NFD, а в случаях анализа произвольных юникодных строк на похожесть NFD намного удобнее) или подобным извращением. И я не уверен, что нужно считать канонически эквивалентные (особенно в случае NFC vs NFD, где у них длина может быть разной) строки разными в твоей задаче. Нет, тупо применить алгоритм можно, но результат может быть не тем, что искали.

x3al ★★★★★
()
Ответ на: комментарий от x3al

Просто СИМВОЛ может оказаться знаком ударения, нулевым пробелом, нулевым неразделителем, мягким переносом, комбинирующим умлаутом (если NFD, а в случаях анализа произвольных юникодных строк на похожесть NFD намного удобнее) или подобным извращением.

согласен. Но в русском/английском языке всё работает более-менее. С «ё» правда проблемы возникают. (потому меня бесит, когда её не ставят где надо, ЛЮТО БЕШЕНО НЕНАВИЖУ).

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

ИМХО нужно везде utf-8 юзать. Ну кроме особых случаев.

emulek
()
Ответ на: комментарий от emulek

Ну да, если так — согласен. Правда, я бы запихнул их хотя бы в uint32 (а лучше — какую-нибудь стандартизованную вещь вроде gunichar, заtypedef'ленную на uint32 в данный момент).

x3al ★★★★★
()
Ответ на: комментарий от x3al

Ну да, если так — согласен. Правда, я бы запихнул их хотя бы в uint32 (а лучше — какую-нибудь стандартизованную вещь вроде gunichar, заtypedef'ленную на uint32 в данный момент).

дык разве wchar_t не для этого? У меня оно как раз uint32_t. ИМХО очень удобно, есть и готовые функции, что-бы велосипеды не изобретать. Ну например wcscmp(3), которая часто работает намного быстрее memcmp(3), потому-что не обмазывается случаями, когда байты не делятся на 4 и когда они не выровнены на границу 4.

emulek
()
Ответ на: комментарий от anonymous

цитата:

Для последней версии CityDesk, программного обеспечения для управления веб-сайтом, выпускаемого моей компанией, мы решили сделать все внутренние строки в кодировке UCS-2 (двухбайтовой) Unicode, которая является родной для кодировки строк в Visual Basic, COM, и Windows NT/2000/XP. В коде на C++ мы просто объявляем строки как wchar_t («широкий символ», «wide char») вместо char и используем wcs-функции вместо str-функций (например wcscat и wcslen вместо strcat и strlen). Для того, чтобы в С создать строку в кодировке UCS-2, надо всего лишь поместить перед строкой L, вот так: L"Hello".

всё верно, кроме одного: 16 бит в wchar_t — очередной глюк маздая. Туда моя любимая ☣ не влезает. Я в печали...

emulek
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.