[C++] Počet znaků v českém řetězci

C++, C#, Visual Basic, Delphi, Perl a ostatní

Moderátor: Moderátoři Živě.cz

Odeslat příspěvekod PiranhaGreg 11. 1. 2015 15:53

Zdravím,

poprvé jsem nucen pracovat v C++ s českými řetězci. A nemile mě překvapilo, že např. kód

Kód: Vybrat vše
#include <iostream>
#include <string>

using namespace std;

int main(void) {
   string a = "Příliš žluťoučký kůň úpěl ďábelské ódy";
   string b = "Prilis zlutoucky kun upel dabelske ody";

   cout << "a: " << a.length() << endl;
   cout << "b: " << b.length() << endl;

   return 0;
}

vrátí výsledek

Kód: Vybrat vše
a: 53
b: 38

Existuje někde nějaká sada funkcí, se kterou tohle není problém? Vím, že existuje wchar (atd.), ale ten nemůžu použít (a co jsem četl, tak se to stejně ani moc nedoporučuje). Mám jistotu, že v těch řetězcích budou jen české znaky a potřebuji jen funkce length, find a substr. V nejhorším si to naimplementuju. Českých znaků s diakritikou naštěstí není moc... Ale nějaké hotové řešení bych uvítal víc O:-) .
PiranhaGreg
Mírně pokročilý
Uživatelský avatar

Odeslat příspěvekod soban 11. 1. 2015 16:27

A co je na tom špatně?

Přece délka řetězce je správná čili length funguje správně, pokud chceš zjistit počet znaků a používáš pro zápis vicebajtové znaky tak to prostě musíš počítat po těch znacích podle toho jaké kodování používáš zda UTF8, UTF16 atd.....

Viz:

Kód: Vybrat vše
petr@NT-Olomouc:/tmp$ ls -l *.txt
-rw-rw-r-- 1 petr petr 54 led 11 16:30 text.txt
petr@NT-Olomouc:/tmp$ cat text.txt
Příliš žluťoučký kůň úpěl ďábelské ódy


Text "Příliš žluťoučký kůň úpěl ďábelské ódy" má 54B protože na rozdíl od C++ v textovém editoru nemám na konci 0x00 která se nepočítá do délky řetězce ale mám tam konec řádku 0x0A.

Viz:

Kód: Vybrat vše
petr@NT-Olomouc:~$ hexdump -C /tmp/text.txt
00000000  50 c5 99 c3 ad 6c 69 c5  a1 20 c5 be 6c 75 c5 a5  |P....li.. ..lu..|
00000010  6f 75 c4 8d 6b c3 bd 20  6b c5 af c5 88 20 c3 ba  |ou..k.. k.... ..|
00000020  70 c4 9b 6c 20 c4 8f c3  a1 62 65 6c 73 6b c3 a9  |p..l ....belsk..|
00000030  20 c3 b3 64 79 0a                                 | ..dy.|
00000036
petr@NT-Olomouc:~$


Jinak mrkni na http://www.cprogramming.com/tutorial/unicode.html

Na té stránce je zdroják http://www.cprogramming.com/tutorial/utf8.c a http://www.cprogramming.com/tutorial/utf8.h to ti možná pomůže.

Je tam funkce co počítá znaky:

Kód: Vybrat vše
/* returns length of next utf-8 sequence */
int u8_seqlen(char *s);

/* count the number of characters in a UTF-8 string */
int u8_strlen(char *s);

Naposledy upravil soban dne 11. 1. 2015 16:59, celkově upraveno 1
/----------------------------------------\
| Petr Šobáň |
| Olomouc |
\----------------------------------------/
soban
Pokročilý

Odeslat příspěvekod ahorek 11. 1. 2015 16:56

V utf8 se vytvoří něco takového:
"P�\x99íliš žluťou�\x8Dký ků�\x88 úp�\x9Bl �\x8Fábelské ódy" což je opravdu 53 znaků

Lze to vyřešit například takto případně nějakou knihovnou, ale je to mnohem pomalejší než hodnota .length, která je uložena přímo v paměti:
Kód: Vybrat vše
size_t utf8len(char *s)
{
    size_t len = 0;
    for (; *s; ++s) if ((*s & 0xC0) != 0x80) ++len;
    return len;
}


K čemu vůbec potřebuješ pracovat takto se stringy? To chceš něco parsovat?
ahorek
Junior

Odeslat příspěvekod PiranhaGreg 11. 1. 2015 18:42


Jé, díky moc. To jsem přesně potřeboval. Celkově se jedná o hezkej článek :-) .

ahorek píše:K čemu vůbec potřebuješ pracovat takto se stringy? To chceš něco parsovat?

Psal jsem si funkci na správné odřádkování slov. Protože konzole žádný word wrap samozřejmě nedělá. No a s UTF-8 mě to sice taky funguje, ale když je na nějakým řádku hodně diakritiky, tak to zbytečně brzo pokračuje dalším řádkem (i když by se tam třeba jedno slovo ještě vešlo).
PiranhaGreg
Mírně pokročilý
Uživatelský avatar


Kdo je online

Uživatelé procházející toto fórum: Žádní registrovaní uživatelé a 0 návštevníků