Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> strstr, utf8 
V
    Опции темы
chubaka
Дата 26.3.2008, 07:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



Есть обьект std::string string1, содержащий русские символы. Нужно узнать, присутствует ли в нем строка std::string string2, тоже содержащая русские символы. 

С strstr не получается.

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

Это сообщение отредактировал(а) chubaka - 26.3.2008, 07:03
PM MAIL   Вверх
korian
Дата 26.3.2008, 08:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



для utf-8 вот это:
unsigned char * _mbsstr(const unsigned char *s1, const unsigned char *s2);


Это сообщение отредактировал(а) korian - 26.3.2008, 10:17
PM   Вверх
chubaka
Дата 26.3.2008, 08:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



Компилятор gcc, система unix.

mbstring.h не нашел у себя
PM MAIL   Вверх
Dennnis
Дата 26.3.2008, 09:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 145
Регистрация: 23.3.2008

Репутация: нет
Всего: 4



int pos = (int)string1.find(string2.c_str());
if(pos == -1)
{
//не нашел
}
--------------------
Get Rich or Die Tryin'
PM   Вверх
korian
Дата 26.3.2008, 09:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



Цитата(Dennnis @  26.3.2008,  08:43 Найти цитируемый пост)
string1.find(string2.c_str());

угу, я тоже сначала написал что-то подобное  smile 
только у него utf-8

PM   Вверх
chubaka
Дата 26.3.2008, 10:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



korian, именно. find,strstr не работают
PM MAIL   Вверх
korian
Дата 26.3.2008, 10:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



если у вас нету функции:
unsigned char * _mbsstr(const unsigned char *s1, const unsigned char *s2);
я даже хз, что тут посоветовать... имху переходить в ASCII или в UNICODE

PM   Вверх
chubaka
Дата 26.3.2008, 12:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



Немного конкретизировал задачу. Перегнал данные в wchar_t, но всеравно не ищет. Код:

Код

    std::string limit_string, search_for;

    // ..., записываем данные в limit_string и search_for    

    wchar_t *w_limit_string = new wchar_t[limit_string.length()+1];
    wchar_t *w_search_for = new wchar_t[search_for.length()+1];
    size_t my_result;
    my_result = mbstowcs(w_search_for, search_for.c_str(), search_for.length());    
    my_result = mbstowcs(w_limit_string, limit_string.c_str(), limit_string.length());
    
    w_limit_string[limit_string.length()] = '\0';
    w_search_for[search_for.length()] = '\0';
    
    const wchar_t *w_limit_string_const = w_limit_string;
    const wchar_t *w_search_for_const = w_search_for;
    
    if (wcsstr(w_limit_string_const, w_search_for_const))
    {
    std::cout << "true";
    }
    else
    {
    std::cout << "false";
    }
    
    delete [] w_search_for;
    delete [] w_limit_string;

PM MAIL   Вверх
bsa
Дата 26.3.2008, 12:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



А может вместо std::string спользовать std::wstring? С ним все работает.
PM   Вверх
korian
Дата 26.3.2008, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



Цитата(chubaka @  26.3.2008,  11:14 Найти цитируемый пост)
    my_result = mbstowcs(w_search_for, search_for.c_str(), search_for.length());    
    my_result = mbstowcs(w_limit_string, limit_string.c_str(), limit_string.length());
    
    w_limit_string[limit_string.length()] = '\0';
    w_search_for[search_for.length()] = '\0';

а эта функция (mbstowcs) нули сама не ставит?
если у вас limit_string и search_for это объекты std::string'а, то length() для них вычисляется не правильно.
и если надо записывать нули, то надо указывать вайдовский ноль:
w_limit_string[<я хз как длину определить>] = L'\0';

Добавлено @ 13:49
почитал про mbstowcs...
попробуйте так:
Код


    std::string limit_string, search_for;

    // ..., записываем данные в limit_string и search_for    

    unsigned long limit_string_len = _mbslen(limit_string.c_str()); //тут может _mbstrlen, если того нету
    unsigned long search_for_len = _mbslen(search_for.c_str());

    wchar_t *w_limit_string = new wchar_t[limit_string_len];
    wchar_t *w_search_for = new wchar_t[search_for_len];
    size_t my_result;
    my_result = mbstowcs(w_search_for, search_for.c_str(), search_for_len);
    my_result = mbstowcs(w_limit_string, limit_string.c_str(), limit_string_len);
    
    const wchar_t *w_limit_string_const = w_limit_string;
    const wchar_t *w_search_for_const = w_search_for;
    
    if (wcsstr(w_limit_string_const, w_search_for_const))
    {
    std::cout << "true";
    }
    else
    {
    std::cout << "false";
    }
    
    delete [] w_search_for;
    delete [] w_limit_string;


Это сообщение отредактировал(а) korian - 26.3.2008, 13:51
PM   Вверх
chubaka
Дата 26.3.2008, 13:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



korian, на счет нулей - не знаю, просто перестраховался. Пробовал и так и так.

На счет длины - вы не правы. 

Да, char[5] и wchar_t[5] занимают разное количество памяти, но длина текста у них аналогичная. В первом случае каждый символ - 8 бит, во втором - 16.

Добавлено через 2 минуты и 12 секунд
Уверяю вас, дело не в длине. Я проверял вручную переменные которые образовались, значения у них - правильные. 

Это сообщение отредактировал(а) chubaka - 26.3.2008, 13:50
PM MAIL   Вверх
korian
Дата 26.3.2008, 13:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



Цитата(chubaka @  26.3.2008,  12:49 Найти цитируемый пост)
На счет длины - вы не правы. 

прав  smile 
ASCII - для символа 8 бит
UTF-8 (он же мультибайт) - длина символа 8 бит или 16 бит
UTF-16 (он же UNICODE, wchar_t) - длина символа 16 бит.

если использовать функцию ASCII (strlen) для UTF-8, то результат не предсказуем...
хотя может и предсказуем, если знать кодирование в UTF-8, я его не знаю. если в UTF-8 возможет вариант, что один символ записывается как \0xAB\0x00, тогда strlen будет возвращать значение меньше истинной длины. а в общем случае, если такого варианта не может быть, то strlen будет возвращать длину больше реальной.


Это сообщение отредактировал(а) korian - 26.3.2008, 13:56
PM   Вверх
chubaka
Дата 26.3.2008, 14:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



korian, понял =) спасибо )

По поводу вашего примера - _mbslen (также как и _mbsstr, выше писал) - у меня ведь ее нет =)) была бы, я думаю давно решил бы проблему перегоном в unsigned char. 

Где найти mbstring.h и библиотеку для него ? FreeBDS.
PM MAIL   Вверх
korian
Дата 26.3.2008, 14:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



тогда посмотрите значения w_limit_string_const и w_search_for_const
они нормальные? если да, то что-то уж очень все странно...
PM   Вверх
chubaka
Дата 26.3.2008, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



korian, да, нормальные. Но русский в w_limit_string_const - кракозябрами, а в w_search_for_const - нормальный. Хочу перегнать в unsigned char, но нужна _mbsstr.
PM MAIL   Вверх
korian
Дата 26.3.2008, 14:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



а такая функция есть? - mblen
PM   Вверх
chubaka
Дата 26.3.2008, 14:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



Да. Попробую с ней

Это сообщение отредактировал(а) chubaka - 26.3.2008, 14:12
PM MAIL   Вверх
marcusmae
Дата 26.3.2008, 15:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


Профиль
Группа: Участник
Сообщений: 874
Регистрация: 26.3.2006

Репутация: 5
Всего: 39



Цитата(chubaka @  26.3.2008,  07:01 Найти цитируемый пост)
Как можна решить задачу максимально просто ?


Имхо, максимально просто - это прекратить рассматривать мультибайтовые чары и перейти к их представлению, как указатели на байтовые массивы. Сначала нам нужна функция, которая будет в массиве байт находить по эталону два последовательных байта (два байта - это, по определению, представление для кириллицы в utf-8).

Код

// Get the source string UTF-8 2-byte octet first occurence index.
int IndexOfCyr(char* source, const unsigned int sourceLength,
               char first, char second) {

    for (unsigned int index = 0; index < sourceLength - 1; index++)
        if ((source[index] == first) && (source[index+1] == second))
            return index;
    return -1;
}


Далее, нужна функция, которая будет в массиве байт находить эталонную последовательность пар байт.

Код

// Get the source string UTF-8 2-byte octets sequence first occurence index.
int IndexOfCyr(char* source, const unsigned int sourceLength,
               char* word, const unsigned int wordLength) {

    int index = IndexOfCyr(source, sourceLength, *word, *(word + 1));
    
    if (wordLength == 2) return index;

    while ((index != - 1) && (sourceLength - index >= wordLength - 2))
    {
        if (memcmp((const void*)(source + index + 2), (const void*)(word + 2),
            wordLength - 2) == 0) return index;

        index++;
        index = IndexOfCyr(source + index, sourceLength - index, *word, *(word + 1));
    }
    return -1;
}


Ключевая функция - memcmp - сравнение байтовых последовательностей.

Для проверки, строки я ввожу из файлов в формате UTF-8 :

string.txt
Цитата

The quick коричневая лисица jumps over the lazy dog


substring.txt
Цитата

коричневая лисица


Файлы - в UTF-8, но читаю, как байты :

Код

// Load byte array from the file with the specified name.
char* LoadBytes(const char* filename, int* size) {

    // Get the file size in bytes.
    struct _stat filestat;
    _stat(filename, &filestat);

    // Open file, alloc array, read bytes and close file.
    ifstream file(filename, ios_base::binary | ios_base::in);
    char* fileStream = new char[filestat.st_size];
    file.read(fileStream, filestat.st_size);
    file.close();

    *size = filestat.st_size;

    return fileStream;
}


В результате, для приведённых файлов

Код

int _tmain(int argc, _TCHAR* argv[])
{
    const int utfHeaderOffset = 3;

    int
        stringSize,
        substringSize;

    char
        *string = LoadBytes("string.txt", &stringSize),
        *substring = LoadBytes("substring.txt", &substringSize);

    cout << IndexOfCyr(string + utfHeaderOffset, stringSize - utfHeaderOffset,
        substring + utfHeaderOffset, substringSize - utfHeaderOffset);

    delete string, substring;

    cin.get();

    return 0;
}


ответом является
Цитата

10


то есть, коричневая лисица началась с десятой позиции в строке.

В примечание - utfHeaderOffset - некий маркер utf-формата, который можно отладчиком увидеть в обоих строках. Мы должны его перепрыгнуть, иначе совпадений не будет найдено (-1).

Вроде не очень сложно, да?..

Это сообщение отредактировал(а) marcusmae - 26.3.2008, 15:18

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  CyrUTF8.rar 179,63 Kb


--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
chubaka
Дата 27.3.2008, 08:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



marcusmae, спасибо огромное за такой полный ответ, но мне не помогло.
Исходная задача такая: есть 2 std::string обьекта. Они не загружаются из файла. Они через сокеты получают данные от другого сервера. Отсюда видимо значит что и маркера UTF формата не будет. 

 smile 

Это сообщение отредактировал(а) chubaka - 27.3.2008, 09:00
PM MAIL   Вверх
korian
Дата 27.3.2008, 09:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



Цитата(chubaka @  27.3.2008,  07:59 Найти цитируемый пост)
Отсюда видимо значит что и маркера UTF формата не будет.

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

Это сообщение отредактировал(а) korian - 27.3.2008, 09:38
PM   Вверх
chubaka
Дата 27.3.2008, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



korian, про маркеры писал ув. marcusmae.

limit_string - HTML страница, полученная CURL'ом.
search_for - данные из файла, для поиска в коде HTML страницы. Загружается ifstream'ом. 
PM MAIL   Вверх
korian
Дата 27.3.2008, 09:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 3
Всего: 17



Цитата(chubaka @  27.3.2008,  08:45 Найти цитируемый пост)
korian, про маркеры писал ув. marcusmae.

он писал что его надо перепрыгнуть, т.к. он нам нафиг не нужен, т.к. мы из начально знаем что там UTF-8. а по стандарту он туда пишется.
если файл из которого читается search_for - UTF-8
и search_for - это std::string, а ifstream - это std::ifstream, и читается оно по типу ifstream.getline(search_for), то у вас из начально не правильные значение в search_for.

Это сообщение отредактировал(а) korian - 27.3.2008, 09:59
PM   Вверх
Rififi
Дата 27.3.2008, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1254
Регистрация: 9.3.2008

Репутация: 11
Всего: 36



chubaka, 
C/C++ рантайм не поддерживает работу с utf-8.
поэтому перед использованием текст надо перекодировать в честный utf-16 и юзать W-функции
см. MultiByteToWideChar
PM MAIL   Вверх
chubaka
Дата 27.3.2008, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 8.6.2007

Репутация: нет
Всего: нет



korian, уважаемый, вы гений =) Огромное спасибо. Действительна проблема была в том, что я неверно вводил данные в файл. Я программирую на удаленном сервере через SSH, и клиент PuTTy неверно принимал русские символы. Спасибо большое !

Также спасибо большое всем кто старался помочь. Много полезных советов на будущее  smile 
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1997 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.