2014-01-06 2 views
0

Я хочу сделать некоторые простые манипуляции с строками в текстовом файле utf8. Это будет означать взятие подстрок из строки и вывод их перегруппировки.C++ string manipulation with the utf8 locale

Как мой Linux-компьютер имеет языковой стандарт utf8, и я не намерен запускать программу в другом месте, поскольку locale to utf8, казалось, был для вас способом. Адаптация примера, который я привел в тестовую программу ниже. Если вы даете ему греческое слово, оно выводит то же самое, но вывод результата substr просто производит мусор. Есть ли еще одна функция, которую я могу использовать или использую локаль utf8 полностью неправильным способом?

#include <string> 
    #include <iostream> 

    int main() 
    { 
     std::string newwd; 
     setlocale(LC_ALL, ""); 
     std::cout << "Enter greek word "; 
     std::string wordgr; 
     std::getline(std::cin, wordgr); 
     std::cout << "The word is " << wordgr << "." << std::endl; 
     newwd=wordgr.substr(2,1) ; 
     std::cout << "3rd letter is " << wordgr.substr(2,1) << " <" << std::endl; 
     return 0; 
    } 
+5

UTF-8 - кодирование переменной длины; данный символ в UTF-8 может составлять от одного до шести байтов. Это вызывает метод substr(), который работает с байтами, а не с символами * для получения неожиданных результатов. Греческие символы в UTF-8 не являются однобайтными символами. Если вы введете 4-значную греческую строку, а затем на это слово вызывается 'std :: string.length()', вы получите результат больше 4 байтов (скорее всего, 8 байтов). –

+2

@KenP Вы должны разместить это как ответ. :) – 0x499602D2

+0

Очень простое решение - переключиться на wstring и wiostream и wchar_t. –

ответ

0

Если вы будете использовать UTF-8 в ваших приложениях вы должны рассмотреть соответствующую библиотеку: utf8-cpp. std :: string или std :: wstring не является опцией, так как символы UTF-8 могут иметь переменную длину, отметьте wiki для получения дополнительной информации.

Вот пример кода, подтверждающего эту концепцию.

#include <string> 
#include <iostream> 
#include "source/utf8.h" // path to the utf8-cpp library header 

int main() 
{ 
     setlocale(LC_ALL, ""); 
     std::cout << "Enter greek word "; 
     std::string wordgr; 
     std::getline(std::cin, wordgr); 
     std::cout << "The word is " << wordgr << "." << std::endl; 
     std::string::iterator end_it = utf8::find_invalid(wordgr.begin(), wordgr.end()); 
     if (end_it != wordgr.end()) { 
       std::cout << "Invalid utf-8 encoding" << std::endl; 
       return 0; 
     } 
     // utf-8 string length 
     std::cout << "Length is " << utf8::distance(wordgr.begin(), end_it) << std::endl; 

     // utf-8 string symbol traverse 
     std::string::iterator curr_it = wordgr.begin(); 
     std::string::iterator next_it = curr_it; 
     utf8::next(next_it, wordgr.end()); 
     while(curr_it != wordgr.end()) { 
       std::cout << std::string(curr_it, next_it) << " - "; 
       curr_it = next_it; 
       if (next_it != wordgr.end()) { 
         utf8::next(next_it, wordgr.end()); 
       } 
     } 
     return 0; 
} 

Выход выглядит следующим образом:

./a.out 
Enter greek word Вова 
The word is Вова. 
Length is 4 
В - о - в - а - 
+0

@ n.m .: Как это неправильно? Даже более широкий тип CharT не может изменить фундаментальный факт, что 'std :: basic_string' является _not_ контейнером символов Unicode и не может быть одним из них. Вам нужна абстракция сверху. –

+0

@LightnessRacesInOrbit Для рассматриваемой реализации 'std :: wstring' * является * контейнером кодов Unicode. Codepoints не являются довольно символами, но utf8-cpp предлагает только коды. –

+0

@ n.m .: Хорошо, тогда ответ неверен, потому что utf8-cpp не является решением :) Спасибо –

2

UTF-8 представляет собой кодирование с переменной длиной; данный символ в UTF-8 может составлять от одного до шести байтов. Это вызывает метод substr(), , который работает с байтами, а не с символами для получения неожиданных результатов. Греческие символы в UTF-8 не являются однобайтными символами. Если вы введете 4-значную греческую строку и затем на это слово назовете std::string.length(), вы получите результат больше 4 байтов (скорее всего, 8 байтов).

1

Это работает в моей системе and on IDEOne.

#include <string> 
#include <iostream> 

int main() 
{ 
    std::wstring newwd; 
    setlocale(LC_ALL, ""); 
    std::wcout << "Enter greek word "; 
    std::wstring wordgr; 
    std::getline(std::wcin, wordgr); 
    std::wcout << "The word is " << wordgr << "." << std::endl; 
    newwd=wordgr.substr(2,1) ; 
    std::wcout << "3rd letter is " << wordgr.substr(2,1) << " <" << std::endl; 
    return 0; 
} 
+0

Хороший простой пример. Огромное спасибо. – daivid

+0

Он работает неправильно и отображает «Третья буква ** ** ** <" вместо «Третья буква ** ** ** <» – vershov

+0

@vershov. Ваш язык по умолчанию, вероятно, не UTF-8. Каков ваш ввод (шестнадцатеричный дамп)? –