LINUX.ORG.RU

C++ преобразовать русскую строку в нижний регистр

 


0

1

Не выходит преобразовать строку с русским текстом к нижнему регистру, для латиницы все работает, а вот кириллица нет. Код такой:

setlocale(LC_ALL,"Russian");
string source = "GNU Linux РуСсКиЙ ТеКсТ";
for ( size_t i = 0; i < source.length(); ++i ) {
source[i] = towlower(source[i]);
}
Как еще можно преобразовать русскую строку в нижний регистр?


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

конечно не работает - у тебя utf8 в файле, а ты по одному _байту_ конвертируешь символы функцией для utf32 (в линуксе), используй wstring и данные ему подсовывай корректные, например с wcin

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

Эммм... если я правильно сделал, то не работает, а сделал так:

std::string source = "GNU Linux РуСсКиЙ ТеКсТ";
wstring ws ( source.begin(), source.end() );
std::transform(ws.begin(), ws.end(), ws.begin(), ::tolower);
string sss( ws.begin(), ws.end() );
cout << sss;

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

:) Как пожелаешь. Можно и тянуть... профитов больше будет. :)

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

неправильно, ты перегнал байты в wstring, а не символы, для этого надо либо брать use_facet, но это ненадежно, либо перегнать руками UTF8->UTF32(16 на win), это не так сложно, либо взять QtCore, советую последнее

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

wcout

Хе, и так тоже не работает:

setlocale(LC_ALL, "ru_RU.UTF-8");
string source = "GNU Linux РуСсКиЙ ТеКсТ";
wstring ws (source.begin(), source.end());
transform(ws.begin(), ws.end(), ws.begin(), ::tolower);
wcout << ws;

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

Ага, в консольное приложение тянуть кют?

почему нет? оно модульное, и не храни русский текст вообще в коде, это моветон, и при правке в каком-нибудь «блокноте» слетит нахер

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

и не храни русский текст вообще в коде, это моветон

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

makeB ()
Ответ на: комментарий от makeB
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;

Ведь гораздо сложнее чем QString::toLower... оно тебе надо? :)

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

Лично я хз о чем вы :) У меня вообще ничего не работает

/usr/include/c++/4.2.1/bits/stl_function.h: In instantiation of 'std::binder2nd<std::pointer_to_binary_function<wchar_t, const std::locale&, wchar_t> >':
../untitled/main.cpp:10:   instantiated from here
/usr/include/c++/4.2.1/bits/stl_function.h:435: error: forming reference to reference type 'const std::locale&'
/usr/include/c++/4.2.1/bits/stl_function.h: In function 'std::binder2nd<_Operation> std::bind2nd(const _Operation&, const _Tp&) [with _Operation = std::pointer_to_binary_function<wchar_t, const std::locale&, wchar_t>, _Tp = std::locale]':
../untitled/main.cpp:10:   instantiated from here
/usr/include/c++/4.2.1/bits/stl_function.h:455: error: no matching function for call to 'std::binder2nd<std::pointer_to_binary_function<wchar_t, const std::locale&, wchar_t> >::binder2nd(const std::pointer_to_binary_function<wchar_t, const std::locale&, wchar_t>&, const std::locale&)'
/usr/include/c++/4.2.1/bits/stl_function.h:429: note: candidates are: std::binder2nd<std::pointer_to_binary_function<wchar_t, const std::locale&, wchar_t> >::binder2nd(const std::binder2nd<std::pointer_to_binary_function<wchar_t, const std::locale&, wchar_t> >&)
../untitled/main.cpp: At global scope:
../untitled/main.cpp: In instantiation of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>, _Alloc = std::allocator<wchar_t>]':
../untitled/main.cpp:11:   instantiated from here
../untitled/main.cpp:11: error: explicit instantiation of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>, _Alloc = std::allocator<wchar_t>]' but no definition available
../untitled/main.cpp: In instantiation of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>, _Alloc = std::allocator<wchar_t>]':
../untitled/main.cpp:11:   instantiated from here
../untitled/main.cpp:11: error: explicit instantiation of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>, _Alloc = std::allocator<wchar_t>]' but no definition available
bhfq ★★★★★ ()
Ответ на: комментарий от bhfq

Ну что за люди :)

#include <iostream>
#include <algorithm>
#include <locale>
#include <functional>

int main(){
    setlocale(LC_ALL, "ru_RU.UTF-8");
    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;
    return 0;
}

g++ t.cpp -o t
./t
some русский тексн

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

а алгоритм же, сам написал и сам забыл да

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

угу, это по факту вариант с use_facet, с тем недостатком, что если на ОС не установлена поддержка нужной локали - полетит исключение, а так да - для ТС наверное это лучшее решение, если он не хочет возится с icu

П.С. меня выше по топику вообще не туда понесло насчет UTF, так что ТС надо послушать первого анонимуса или zJes

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

Гхм, по моему самый простой вариант: нафигачить алфавит в двух экземплярах регистров, и каждую букву в строке сверять, заменять буквой из алфавита с нижним регистром :D

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

Ну видишь, все просто замечательно работает. :)

Неа, разные результаты:

some @CAA:89 B5:A=
some2 @CAA:89 B5:AB
В первом случае some Русский тексн\n, во втором some2 русский текст\n

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

Оооо... я уже гнать начал, опечатался и получил разные результаты :]

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

Ну вооббщем-то все работает, только не так как нужно. Смысле я так и не понял, как преобразовать string в wstring, так:

string sss = "some Русский текст\n";
std::wstring ws (sss.begin(),sss.end());
работает, но не работает преобразование в нижний регистр, то есть, не хватает ключа L, а как с ним сделать преобразование из string в wstring непонятно, в гугле не удалось найти.

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

поиск слов нужен независимо от регистра

Тогда обращу внимание ещё на одну особенность Unicode и UTF-8 в части латиницы с диакритикой:

Один и тот же символ (codepoint), например, ä может быть представлен как:
-- один двухбайтовый символ: 0xC3 0xA4
-- символ плюс комбинируемая диакритика: 'a' 0xCC 0x88

http://en.wikipedia.org/wiki/Combining_character http://en.wikipedia.org/wiki/Unicode_normalization

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

Может проще все-таки утащить QtCore в консольное приложение?

В любом случае стоит найти решение без Qt. Можете выложить сорцы Qt отвечающие за toLower()? Посмотреть как они это сделали...

makeB ()

Я бы заюзал glib для utf-8.

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

Не уверен, что это сильно поможет, но вот:

QString QString::toLower() const
{
    const ushort *p = d->data;
    if (!p)
        return *this;
    if (!d->size)
        return *this;

    const ushort *e = d->data + d->size;

    // this avoids one out of bounds check in the loop
    if (QChar(*p).isLowSurrogate())
        ++p;

    while (p != e) {
        uint c = *p;
        if (QChar(c).isLowSurrogate() && QChar(*(p - 1)).isHighSurrogate())
            c = QChar::surrogateToUcs4(*(p - 1), c);
        const QUnicodeTables::Properties *prop = qGetProp(c);
        if (prop->lowerCaseDiff || prop->lowerCaseSpecial) {
            QString s(d->size, Qt::Uninitialized);
            memcpy(s.d->data, d->data, (p - d->data)*sizeof(ushort));
            ushort *pp = s.d->data + (p - d->data);
            while (p < e) {
                uint c = *p;
                if (QChar(c).isLowSurrogate() && QChar(*(p - 1)).isHighSurrogate())
                    c = QChar::surrogateToUcs4(*(p - 1), c);
                prop = qGetProp(c);
                if (prop->lowerCaseSpecial) {
                    int pos = pp - s.d->data;
                    s.resize(s.d->size + SPECIAL_CASE_MAX_LEN);
                    pp = s.d->data + pos;
                    const ushort *specialCase = specialCaseMap + prop->lowerCaseDiff;
                    while (*specialCase)
                        *pp++ = *specialCase++;
                } else {
                    *pp++ = *p + prop->lowerCaseDiff;
                }
                ++p;
            }
            s.truncate(pp - s.d->data);
            return s;
        }
        ++p;
    }
    return *this;
}

При этом QChar'овские функции вообще ни о чем не говорят

static inline uint surrogateToUcs4(ushort high, ushort low) {
        return (uint(high)<<10) + low - 0x35fdc00;
}

static inline uint surrogateToUcs4(QChar high, QChar low) {
        return (uint(high.ucs)<<10) + low.ucs - 0x35fdc00;
}

inline bool isHighSurrogate() const {
        return ((ucs & 0xfc00) == 0xd800);
}

inline bool isLowSurrogate() const {
        return ((ucs & 0xfc00) == 0xdc00);
}

Так что я либо просто стащил бы QtCore, либо разбирался, почему не работают приведенные выше примеры на чистых плюсах...

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

Ага, в консольное приложение тянуть кют?

QtCore вполне себе консолен. Ради одной только конвертации регистра символов тащить, конечно, не нужно.

x_hash ()

Ох, ЛОЛ!

Я балдею от этого треда...

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;
int main (){    
    setlocale(LC_ALL,"ru_RU.UTF-8");
    wstring wstrTest = L"Это РуСсКИЙ теКст\n";    
    transform(wstrTest.begin(), wstrTest.end(), wstrTest.begin(),towlower);    
    wcout<<wstrTest;   
    return 0;
}
no-such-file ★★★★★ ()
Ответ на: Ох, ЛОЛ! от no-such-file

Угу, а теперь конвертируй string в твой wstring, причем с учетом того, что string это запись из текстового файла. <Как ты укажешь L интересно? А без нее ничего не выйдет.

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