• C++ Сдаюсь, прошу подсказки. Есть std::string, в ней юникодная строка. Нужно узнать длину строки в символах (не байтах) и обрезать до 130 символов. На выходе нужен char *.
    std::wstring::substr у меня почему-то аккуратно нарезал 130 байт. Конвертировал string в wstring и обратно через assign(begin,end).

Replies (28)

  • @ugnich, в std::string не бывает юникодных строк. Читай Джоэла.
  • @ugnich, если не ошибаюсь то стринг это массив тоесть шобы узнать длинну то берем каунт(строка)
  • @ugnich, @buddax2 В Юникоде символ != байт. Идите в википедию
  • @ugnich, @dottedmag У меня — бывают. :)
  • @ugnich, @ugnich сорри, а когда ты выкатываешь в этом случае новую версию джуйка, на C++? Я постараюсь свалить раньше.
  • @ugnich, @dottedmag или это не джуйк? тогда можно дышать спокойно.
  • @ugnich, @jetxee про что я и говорю: в std::string не бывает юникода, а лишь поток байт в какой-то определённой кодировке.
  • @ugnich, @dottedmag Где я писал, что у меня wchar в string-е? Не придирайтесь к словам.
  • @ugnich, @ugnich именно что не wchar, значит там и юникода быть не может, а только binstream.
  • @ugnich, @dottedmag Капитан Очевидность? :)
    "юникодная строка" = "строка в кодировке юникод".
  • @ugnich, @ugnich нет "кодировки юникод".
  • @ugnich, @jetxee Пару минут назад как раз смотрел эту ссылку, а ник автора не заметил. Интернет тесен. :) Спасибо.
  • @ugnich, @dottedmag есть UCS-4, UTF-8, UTF-16BE и ещё куча разных. А "кодировки юникод" нету.
  • @ugnich, @dottedmag И все эти кодировки такие популярные и так широко используются в jabber, что просто ужас, какая дикая оплошность с моей стороны — не указать в МИКРО блоге конкретное название.
  • @ugnich, Не понимаю: зачем для этого конвертировать в wstring или в UTF-16? По-моему, проще написать функцию, которая возвращает итератор на начало символа №131 для кодировки UTF-8, а потом удалить остальное. Оно и работать будет быстрее...
  • @ugnich, @sandy Может и так, но я надеялся обойтись без написания своих функций.
  • @ugnich, @ugnich Ну я могу написать. :)
  • @ugnich, @sandy Лучше покритикуйте: dumpz.org
  • @ugnich, а локаль в системе точно UTF-8? в принципе, отличия символов от байтов можно узнать только из локали, с учётом текущей кодировки
  • @ugnich, @ugnich Критикую:

    1. После вычисления icut продолжать цикл бессмысленно, или ты удостоверяшься, что там есть ещё хотя бы 3 символа? а если он там всего 1, то i достигнет len раньше, чем cnt своего cntmax, и последнее условие не выполнится.

    2. Если mid.length() >= 122, то цикл не выполнится, мусор в icut;
    если 120 или 121, то цикл выполнится один или два раза, но icut не вычислит;
    если ещё меньше, то как то оно будет работать, но имхо с учётом предыдущего замечания проверять cnt<cntmax в цикле нет необходимости, увеличиваясь по 1, cnt его не перепрыгнет, а остановится на 3 шага раньше.

    3. Я правильно понимаю, что если подать на вход текст на японском с четырёхбайтными символами, твой код поведёт себя совершенно неадекватно?
  • @ugnich, @cblp 1. Да, верно. Если там окажется cntmax-1 символов, то обрезать не нужно будет и точки не понадобятся. А icut нужен, потому что я не знаю, сколько байт нужно заменить на "..." — не всегда нужно "отматывать" ровно на 3 байта.
    2. mid.length() — это длина номера сообщения (115375) — 6 символов.
    3. "Совершенно неадекватно" = "обрежет немного раньше, чем надо". :) Но вообще надо будет переделать, конечно же.
  • @ugnich, @ugnich Если без лишних проверок, то можно как-то так...

    // returns number of chars in the UTF-8 consequence
    char GetNumCharsUTF8(char c){
    char n = 7;
    while(c>>n--&1)
    if(!n) return 1; // c==-1 UTF8 error
    if(n==6) return 1; // normal 7bit
    if(n==5) return 1; // error: prefix cannot be 10xxxxxx
    return 6-n; // total number of chars
    }

    // returns iterator to the next UTF-8 char
    string<char>::iterator NextUTF8Sym(const string<char>::iterator& i){
    return i+GetNumCharsUTF8(*i);
    };

    И NextUTF8Sym вызывается нужное число раз...
    (код не тестировал)
  • @ugnich, Не совсем на си++, но смысл ясен: i=0; foreach(c in string) i += (c<=0x7F) | (c>=0xC0); // дело в том, что коды 0..7F — однобайтовые, а коды С0..FD — начала многобайтовых симводов (их ровно по одному на каждый многобайтовый символ).
  • @ugnich, @vovanium Да, правильно, так даже проще. Если проверять валидность UTF8 не нужно...

    // returns iterator to for the num char of UTF8 string
    string<char>::iterator UTF8Char(string<char>::iterator i, size_t num){
    while(num--)
    while(*i++>>7&1)
    if(!*i) return i; // error or end?
    return i;
    }
  • @ugnich, @sandy Да, в начале проверку забыл... :)

    string<char>::iterator UTF8Char(string<char>::iterator i, size_t num){
    if(!*i) return i; // error or end?
    while(num--)
    while(*i++>>7&1)
    if(!*i) return i; // error or end?
    return i;
    }
  • @ugnich, @sandy Спасибо, но уже по-другому сделал. Посмотреть можно тут: code.google.com
  • @ugnich, @ugnich То есть, китайцев дискриминируем. Ну, хозяин — барин. :)