LINUX.ORG.RU

С++ конвертация unsigned char

 


0

1

В продолжение прошлого топика, где решение так и не нашли. Итак, пытаюсь поменять регистр строки, путем прибавления, убавления hex-кода у каждого символа. По идее должно все корректно работать:

setlocale(LC_ALL, "ru_RU.UTF-8");
int i = 0;
string ts = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЭЮЯ!";
char sc[256];
strcpy( sc, ts.c_str() );
while(sc[i]) {
if((unsigned char)sc[i] >= 0x90 && (unsigned char)sc[i] <= 0x9f ) sc[i] = (unsigned char)sc[i] + 0x20;
if((unsigned char)sc[i] >= 0xa0 && (unsigned char)sc[i] <= 0xaf ) sc[i] = (unsigned char)sc[i] - 0x20;
i++;
}
cout << sc << endl;
Но работает не корректно, начиная от буквы П, выводит символы не нижнего регистра, а какие-то левые. вывод в консоли:
абвгдеЁжзийклмнопЀЁЂЃЄЅІЇЈЉЊЌЍЎЏ!
а должен по идее вывести весь алфавит в нижнем регистре. В чем причина? Как исправить? Кто еще что может посоветует, для перевода строки в нижний регистр?


Может коды у букв начиная с «п» другие?

Точно, ты отнимаешь не в ту сторону. Смотри таблицу символов: http://www.utf8-chartable.de/unicode-utf8-table.pl?start=1024

У тебя для «п» получается d080 вместо d0 bf

hope13 ★★★
()
Последнее исправление: hope13 (всего исправлений: 2)

Если чо, то не бейте. А разве utf8 можно запихать в чар? Там помоему динамический размер символа, но русские же вроде как раз занимают больше 8.

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

Там все верно, просто у меня получается (начиная с Р) d0 80 вместо d1 80, а вот как сделать чтоб d1(!) 80 получалась, я не как не дотумкаю...

makeB
() автор топика

Гхм, неужели ни кто не знает?

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

Вот, держи. Сделал как смог:

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

int main()
{
  setlocale(LC_ALL, "ru_RU.UTF-8");
  int i = 0;
  wchar_t widets[] = L"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЭЮЯ!";

  while(widets[i]){
    if((wchar_t)widets[i] >= 1040 && (wchar_t)widets[i] <= 1071 ) widets[i] = (wchar_t)widets[i] + 32;
    i++;
  }

  for(i=0;i<33;i++)
    printf("%lc\n",widets[i]);
}

Как я и говорил во втором условии нужно тоже прибавлять 32 а не отнимать(посмотри ещё раз на таблицу).

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

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

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

С char'ом у тебя тем более ничего не выйдет. Выше уже объяснили.

wchar не подходит, ибо в него невозможно конвертировать строку с литералом L.

Не понял - поясни.

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

Не понял - поясни.

Мне нужно преобразовать именно строку и сравнивать именно строку, как ее преобразовать — без разницы, хоть через wchar, хоть как. Но при этом нужно учитывать, что строка это не string sname = «text»; а vector<string> vname; И как как его преобразовать в wchar да еще с литералом L не имею понятия. В wstring например так wstring ws (vname.begin(), vname.end()), но даже тут неизвестно как вставить литерал L, без которого ничего не выйдет.

То есть, так:

std::wstring ws(L"some Русский тексн");
std::transform(ws.begin(), ws.end(), ws.begin(), std::bind2nd(std::ptr_fun(&std::tolower<wchar_t>), std::locale("ru_RU.UTF-8")));
std::wcout << ws;
tolower сработает, а вот без литерала L перед «some Русский тексн» не сработает. А конвертировать и стринга в встринг можно как уже выше писал, только без литерала L, и в wchar наверняка тоже самое.

makeB
() автор топика

Пишу с телефона, сниппет дать не могу, сорри. Суть такая: берешь последовательно байты 'a', смотришь, если > 0x7f значит началась utf-8 последовательность. Ее надо собрать в один int32. То есть берешь следующий байт 'b' и c = (a & 0x1f) << 6 + (b & 0x3f). Получил Unicode codepoint. Теперь делаешь с ним что нужно, и распаковываешь обратно. Сложно с телефона код писать, глянь сам на википедии utf-8. На работе есть готовый, могу завтра скинуть.

anonymous
()

Если свои наброски есть, сначала убедись, что распаковываешь/упаковка нормально работает, и получается та же строка на выходе. И только потом вставляй код для преобразования регистра.

anonymous
()

setlocale(LC_ALL, «ru_RU.UTF-8»);

И сколько байт по вашему занимает русский символ в памяти? Почитайте про utf-8.

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

А разве utf8 можно запихать в чар?

А почему нет?

Там помоему динамический размер символа, но русские же вроде как раз занимают больше 8.

Больше восьми чего?

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

Их, случаем, не в wchar_t нужно запихивать? Это же многобайтные символы.

«Широко-байтный» и «многобайтный» - это несколько разные понятия. Совсем разные.

andreyu ★★★★★
()

Не знаю, как там у вас в C++, а в С как-то так:

#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
    {
    char *utf_str = "ТАКОЙ вот текст", *u;
    wchar_t *w_str, *w;
    size_t len;

    setlocale(LC_ALL, "ru_RU.UTF8");

    /* To wide string */
    len = mbstowcs(NULL, utf_str, 0);
    w_str = malloc((len + 1) * sizeof(*w_str));
    mbstowcs(w_str, utf_str, len + 1);

    /* To upper */
    for(w = w_str; *w != 0; ++w)
        *w = towupper(*w);

    /* To multibyte string */
    len = wcstombs(NULL, w_str, 0);
    u = malloc((len + 1) * sizeof(*u));
    wcstombs(u, w_str, len + 1);
    
    printf("UPPER: %s\n", u);
    
    /* To lower */
    for(w = w_str; *w != 0; ++w)
        *w = towlower(*w);
    
    /* To multibyte string */
    len = wcstombs(NULL, w_str, 0);
    u = realloc(u, (len + 1) * sizeof(*u));
    wcstombs(u, w_str, len + 1);
    
    printf("lower: %s\n", u);
    
    free(u);
    free(w_str);

    return 0;
    }
cdslow ★★
()
Ответ на: комментарий от andreyu

Он широкобайтный => его код больше 0xff
Он многобайтный => бинарное представление занимает больше 1 байта

И для первых нужен тип wchar_t. Так?

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

Столько лет прошло, а до сих пор путают. Есть unicode — каждому символу из всех в мире возможных дали номер, и этот номер на сегодня точно влезает в 24 бита. Это абстрактно. Конкретно есть кодировки, среди них utf-8, utf-16, utf-32, которые позволяют как-то в потоке чисел разрядностью 8/16/32 бит кодировать эти номера. utf-32 кодирует 1 в 1, но занимает много места. utf-8 кодирует как написано в википедии. Кодирование в wchar_t (широкие буквы) зависит от компилятора и/или стандартной библиотеки (!) и серьезно его воспринимать не стоит. С мультибайтом не работал, не знаю как там.

Кроме того, utf-32 не панацея, так как сам стандарт юникода описывает, что некоторые символы могут быть представлены как комбинации основного глифа и дополнительного (например диакритика). Так что либо используешь icu для общих случаев, либо самостоятельно решаешь частный.

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

Хороший пример, когда в С в отличие от С++ нужно делать вручную: много строк, зато всё явно и понятно.

А в плюсах аналогичное

string utf_str = "ТАКОЙ вот текст";
wstring w_str = utf_str;
//for (wstring::iterator w_it = w_str.begin(); it != w_str.end(); it++)
//   cout << *w_it << " ";
transform(w_str.begin(), w_str.end(), w_str.begin(), ::tolower);
string u = w_str;
cout << u << endl;
не проходит.

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

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

А по поводу wchar_t - это дрянь, которую использовать не стоит. Особенно в windows - там sizeof(wchar_t) равен двум байтам.

andreyu ★★★★★
()

Бугога, запарился, сделал так (профит! :])

#include <boost/algorithm/string/replace.hpp>
using namespace std;

string string_to_lower (string source) {
boost::replace_all(source, "А", "а");
boost::replace_all(source, "Б", "б");
boost::replace_all(source, "В", "в");
boost::replace_all(source, "Г", "г");
boost::replace_all(source, "Д", "д");
boost::replace_all(source, "Е", "е");
boost::replace_all(source, "Ё", "ё");
boost::replace_all(source, "Ж", "ж");
boost::replace_all(source, "З", "з");
boost::replace_all(source, "И", "и");
boost::replace_all(source, "Й", "й");
boost::replace_all(source, "К", "к");
boost::replace_all(source, "Л", "л");
boost::replace_all(source, "М", "м");
boost::replace_all(source, "Н", "н");
boost::replace_all(source, "О", "о");
boost::replace_all(source, "П", "п");
boost::replace_all(source, "Р", "р");
boost::replace_all(source, "С", "с");
boost::replace_all(source, "Т", "т");
boost::replace_all(source, "У", "у");
boost::replace_all(source, "Ф", "ф");
boost::replace_all(source, "Х", "х");
boost::replace_all(source, "Ц", "ц");
boost::replace_all(source, "Ч", "ч");
boost::replace_all(source, "Ш", "ш");
boost::replace_all(source, "Щ", "щ");
boost::replace_all(source, "Ъ", "ъ");
boost::replace_all(source, "Ы", "ы");
boost::replace_all(source, "Ь", "ь");
boost::replace_all(source, "Э", "э");
boost::replace_all(source, "Ю", "ю");
boost::replace_all(source, "Я", "я");
return source;
}

makeB
() автор топика

если у тебя не получилось читать файл, то это делается так:

#include <algorithm>
#include <fstream>
#include <iostream>
#include <locale>
using namespace std;

int main()
{
	setlocale(LC_ALL, "ru_RU.UTF-8");

	wifstream f( "data.txt" );
	f.imbue( locale( "ru_RU.UTF-8" ) );
	while( f.good() )
	{
		wstring s;
		f >> s;
		transform( s.begin(), s.end(), s.begin(), towlower );

		wcout << s << endl;
	}
}
wota ★★
()
Последнее исправление: wota (всего исправлений: 1)
Ответ на: комментарий от gag

А в плюсах аналогичное не проходит.

во-первых «аналогичное» пишется тоже с setlocale, во-вторых towlower - и у тебя все пройдет

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

Если буст, так в нём же есть boost::locale::to_lower.

Он ошибку вызывает, хотя буст локале.хпп подключал, короче уже банально лень разбираться было.

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

<на всякий случай> если читать надо по строкам:

wstring s;
getline( f, s );

</на всякий случай>

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

По мотивам этого:

// $ ./test_boost.cpp <<< 'ТЕКСТ'
// текст

#include <iostream>
#include <locale>
#include <boost/locale.hpp>

int main() {
    boost::locale::generator gen;
    std::locale loc = gen("");
    std::string line;
    while (std::getline(std::cin, line))
        std::cout << boost::locale::to_lower(line, loc) << '\n';
}

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

А в плюсах

во-первых «аналогичное» пишется тоже с setlocale

Тогда уже locale.

Вот если бы ещё то, что выше с бустом, катило и без. А то локаль устанавливаешь, а tolower() это игнорирует.

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

Не думаю, что даже более развернутый пост добавит ясности в умы, где до сих пор неразобрана каша из ansi, char*, TCHAR, cp1251, utf-<n>, wchar_t и LPCTSTR. Такие вещи надо класть в фак или прикреплять в девелопменте. Вместо этого у нас:

 education scala Онлайн-учебники по Scala на русском языке (LongLiveUbuntu) 	21.01.13 15:17	13/-/-
[Прикрепите тему] Собрал проект сторонним(не-gcc) открытым компилятором. (стр. 2) (splinter) 	04.11.12 22:10	68/-/-
tcl tk tck/tk-lor-faq (стр. 2) (Meerkat) 	01.10.12 21:18	70/-/-
lisp-lor-faq (стр. 2 3) (anonymous_incognito)

Очень познавательно и актуально, чо.

anonymous
()

Код "C".

На, длинно зато железно.

#include <stdio.h>


void lover(char sh[255])
{
    
    int counter=0;
    
    while(sh[counter]!='\0')
    
    {  

        (sh[counter]==L'А') ? putchar(L'а'):
        (sh[counter]==L'Б') ? putchar(L'б'):
        (sh[counter]==L'В') ? putchar(L'в'):
        (sh[counter]==L'Г') ? putchar(L'г'):
        (sh[counter]==L'Д') ? putchar(L'д'):
        (sh[counter]==L'Е') ? putchar(L'е'):
        (sh[counter]==L'Ё') ? putchar(L'ё'):
        (sh[counter]==L'Ж') ? putchar(L'ж'):
        (sh[counter]==L'З') ? putchar(L'з'):
        (sh[counter]==L'И') ? putchar(L'и'):
        (sh[counter]==L'Й') ? putchar(L'й'):
        (sh[counter]==L'К') ? putchar(L'к'):
        (sh[counter]==L'Л') ? putchar(L'л'):
        (sh[counter]==L'М') ? putchar(L'м'):
        (sh[counter]==L'Н') ? putchar(L'н'):
        (sh[counter]==L'О') ? putchar(L'о'):
        (sh[counter]==L'П') ? putchar(L'п'):
        (sh[counter]==L'Р') ? putchar(L'р'):
        (sh[counter]==L'С') ? putchar(L'с'):
        (sh[counter]==L'Т') ? putchar(L'т'):
        (sh[counter]==L'У') ? putchar(L'у'):
        (sh[counter]==L'Ф') ? putchar(L'ф'):
        (sh[counter]==L'Х') ? putchar(L'х'):
        (sh[counter]==L'Ц') ? putchar(L'ц'):
        (sh[counter]==L'Ч') ? putchar(L'ч'):
        (sh[counter]==L'Ш') ? putchar(L'ш'):
        (sh[counter]==L'Щ') ? putchar(L'щ'):
        (sh[counter]==L'Ь') ? putchar(L'ь'):
        (sh[counter]==L'Ъ') ? putchar(L'ъ'):
        (sh[counter]==L'Э') ? putchar(L'э'):
        (sh[counter]==L'Ю') ? putchar(L'ю'):
        (sh[counter]==L'Я') ? putchar(L'я'):

        (sh[counter]=='A') ? putchar('a'):
        (sh[counter]=='B') ? putchar('b'):
        (sh[counter]=='C') ? putchar('c'):
        (sh[counter]=='D') ? putchar('d'):
        (sh[counter]=='E') ? putchar('e'):
        (sh[counter]=='F') ? putchar('f'):
        (sh[counter]=='G') ? putchar('g'):
        (sh[counter]=='H') ? putchar('h'):
        (sh[counter]=='I') ? putchar('i'):
        (sh[counter]=='J') ? putchar('j'):
        (sh[counter]=='K') ? putchar('k'):
        (sh[counter]=='L') ? putchar('l'):
        (sh[counter]=='M') ? putchar('m'):
        (sh[counter]=='N') ? putchar('n'):
        (sh[counter]=='O') ? putchar('o'):
        (sh[counter]=='P') ? putchar('p'):
        (sh[counter]=='Q') ? putchar('q'):
        (sh[counter]=='R') ? putchar('r'):
        (sh[counter]=='S') ? putchar('s'):
        (sh[counter]=='T') ? putchar('t'):
        (sh[counter]=='U') ? putchar('u'):
        (sh[counter]=='V') ? putchar('v'):
        (sh[counter]=='W') ? putchar('w'):
        (sh[counter]=='X') ? putchar('x'):
        (sh[counter]=='Y') ? putchar('y'):
        (sh[counter]=='Z') ? putchar('z'): putchar(sh[counter]);
        
        
        
         counter++;
        (sh[counter]=='\0') ? putchar('\n'): 0 ;
        };
    
    
    
    
    };
int main()

{

lover("АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЭЮЯ!");


};

Dron ★★★★★
()
Последнее исправление: Dron (всего исправлений: 1)
Ответ на: Код "C". от Dron

Программа просто эпик на эпике!
Зачем столько "?:" условий? man switch/case
Зачем сравнивать char и wide char напрямую?
Так работать не будет. И возможно даже не скомпилируется(лень проверять)

И вообще «индийский метод» изначально неверный подход.

deadline
()
Ответ на: Код "C". от Dron

класска сайта govnokod.ru :)

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

Вместо того чтобы орать как правильно, а как нет, взял бы да показал как правильно. Буду только благодарен. А тупо кричать все могут.

Код рабочий и не надо фантазировать.

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

А работать должно железно.

в альтернативной ОС, где для хранения L'Я' хватает одного байта, не под досом случайно собираешь?

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

Подобные практики в нормальных проектах могут кончится фатально. Я уверен, что для С++ есть библиотеки, позволяющие это делать правльным способом.

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