C++ - Как читать символы Юникода (например, Hindi Script) с использованием C++ или есть лучший способ через какой-либо другой язык программирования?
У меня есть файл скрипта хинди, как это:
3. भारत का इतिहास काफी समृद्ध एवं विस्तृत है।
Я должен написать программу, которая добавляет позицию к каждому слову в каждом предложении. Таким образом, нумерация для каждой строки для конкретной позиции слова должна начинаться с 1 в скобках. Вывод должен быть примерно таким.
3. भारत(1) का(2) इतिहास(3) काफी(4) समृद्ध(5) एवं(6) विस्तृत(7) है(8) ।(9)
Значение вышеприведенного предложения:
3. India has a long and rich history.
Если вы наблюдаете, что у "।" (который в хинди эквивалентен "." В английском языке) также есть положение слова, и аналогично другие специальные символы также будут иметь место, как я пытаюсь выполнить выравнивание англо-хинди (часть Natural Language Processing ( NLP)), поэтому остановитесь на английском языке "." следует сопоставить с "।" на хинди. Серийные номера остаются без изменений. Я думал, что чтение за символом может быть решением. Не могли бы вы помочь мне с тем, как работать в C++, если это легко или, если проще, можете ли вы предложить какой-то другой путь через какой-то другой язык программирования, например, Python/Perl..?
Дело в том, что я могу получить положения слов для моего английского текста, используя C++, так как я мог читать символ за символом, используя значения ASCII в C++, но у меня нет понятия, как сделать то же самое для текста на хинди.
Конечная цель всего этого состоит в том, чтобы увидеть, какое положение слова в тексте на английском языке соответствует какой позиции на хинди. Таким образом, я могу добиться двунаправленного выравнивания.
Спасибо за ваше время...:)
7 ответов
Я бы серьезно предложил вам использовать Python для такого приложения. Это снимет бремя декодирования стригов (не говоря уже о выделении памяти для них и тому подобное). Вы сможете сосредоточиться на своей проблеме, а не на проблемах языка.
Например, если приведенное выше предложение содержится в файле utf-8, и вы используете python2.x. Если вы используете python 3.x, он становится еще более читабельным, так как вам не нужно ставить префикс юникода как 'u' ', как в этом примере (но вам не хватает многих сторонних библиотек:
separators = [u"।", u",", u"."]
text = open("indiantext.txt").read()
#This converts the encoded text to an internal unicode object, where
# all characters are properly recognized as an entity:
text = text.decode("utf-8")
#this breaks the text on the white spaces, yielding a list of words:
words = text.split()
counter = 1
output = ""
for word in words:
#if the last char is a separator, and is joined to the word:
if word[-1] in separators and len(word) > 1:
#word up to the second to last char:
output += word[:-1] + u"(%d) " % counter
counter += 1
#last char
output += word[-1] + u"(%d) " % counter
else:
output += word + u"(%d) " % counter
counter += 1
print output
Это "развернутый" пример. Поскольку вы все больше привыкаете к Python, есть более короткие способы выразить это. Вы можете выучить основы языка всего за пару часов после обучения. (например, тот, что на самом http://python.org/)
Ух ты, уже 6 ответов, и ни один на самом деле не делает то, что хотел MGJ. JKP подходит близко, но затем бросает мяч, удаляя daṇḍa.
Perl на помощь. Меньше кода, меньше ошибок.
use utf8; use strict; use warnings;
use Encode qw(decode);
my $index;
join ' ', map { $index++; "$_($index)" } split /\s+|(?=।)/, decode 'UTF-8', <>;
# returns भारत(1) का(2) इतिहास(3) काफी(4) समदध(5) एव(6) विसतत(7) ह(8) ।(9)
редактировать: изменено для чтения из STDIN
согласно комментарию, добавлены лучшие практики прагм
Если вы работаете в C++ и решаете, что UTF-8 является жизнеспособной кодировкой для вашего приложения, вы можете взглянуть на utfcpp, которая является библиотекой, которая предоставляет много эквивалентов для типов, найденных в stdlib (таких как потоки и функции обработки строк), но абстрагируется трудности работы с кодировкой переменной длины, такой как UTF8.
Если, с другой стороны, вы можете свободно использовать любой язык, я бы сказал, что сделать что-то подобное в Python будет гораздо проще: поддержка юникода очень хороша, как и процедуры обработки связанных строк.
#!/usr/bin/env python
# encoding: utf-8
string = u"भारत का इतिहास काफी समृद्ध एवं विस्तृत है।"
parts = []
for part in string.split():
parts.extend(part.split(u"।"))
print "No of Parts: %d" % len(parts)
print "Parts: %s" % parts
Выходы:
No of Parts: 9
Parts: [u'\u092d\u093e\u0930\u0924', u'\u0915\u093e', u'\u0907\u0924\u093f\u0939\u093e\u0938', u'\u0915\u093e\u092b\u0940', u'\u0938\u092e\u0943\u0926\u094d\u0927', u'\u090f\u0935\u0902', u'\u0935\u093f\u0938\u094d\u0924\u0943\u0924', u'\u0939\u0948', u'']
Кроме того, поскольку вы выполняете обработку на естественном языке, вы можете взглянуть на библиотеку NLTK для Python, в которой есть множество инструментов именно для такой работы.
ICU - International Components for Unicode - это поддерживаемая IBM библиотека C++, которая начинает становиться стандартом для обработки символов всех языков. Я вижу все больше и больше проектов, использующих его. Это делает работу действительно хорошо. Вот особенности (скопировать / вставить с сайта):
Преобразование кодовойстраницы: Преобразование текстовых данных в или из Unicode и почти любой другой набор символов или кодировки. Таблицы преобразования ICU основаны на данных кодировки, собранных IBM в течение многих десятилетий, и являются наиболее полными из всех доступных.
Сопоставление: сравнивайте строки в соответствии с соглашениями и стандартами конкретного языка, региона или страны. Параметры сортировки ICU основаны на алгоритме сортировки Unicode плюс правила сравнения для конкретных локалей из общего репозитория данных локали, который является исчерпывающим источником данных этого типа.
Форматирование: форматирование чисел, дат, времени и денежных сумм в соответствии с соглашениями выбранной локали. Это включает перевод названий месяцев и дней на выбранный язык, выбор подходящих сокращений, правильное упорядочение полей и т. Д. Эти данные также поступают из хранилища общих языковых данных.
Расчет времени: Несколько типов календарей предоставляются за пределами традиционного григорианского календаря. Предоставляется полный набор API для расчета часовых поясов.
Поддержка Unicode: ICU внимательно следит за стандартом Unicode, обеспечивая легкий доступ ко всем свойствам символов Unicode, нормализации Unicode, складыванию регистра и другим основным операциям, как указано в стандарте Unicode.
Регулярные выражения: регулярные выражения ICU полностью поддерживают Unicode, обеспечивая при этом очень конкурентоспособную производительность.
Bidi: поддержка обработки текста, содержащего смесь данных слева направо (английский) и справа налево (арабский или иврит).
Границы текста: найдите положения слов, предложений, абзацев в пределах диапазона текста или укажите места, которые будут подходить для переноса строк при отображении текста.
Взгляните на http://site.icu-project.org/, библиотеку C++ для обработки строк Unicode.
Самый простой способ сделать это, чтобы получить ваш вклад в std::wstring
(который логически представляет собой массив wchar_t
Теперь у вас все еще не будет "персонажей", потому что эта концепция немного сложнее в хинди. Однако у вас будут подстроки, разделенные L' '
и L'।' также будет отдельным. Например, вы можете позвонить input.find_first_of(L" ।")
Первое, что нужно сделать, это определить, находится ли ваш ввод в UNICODE. Сделайте это, попытавшись прочитать ваш ввод как UNICODE и посмотреть, не искажены ли результаты.
FILE * fp = _wfopen( L"fname",L"r" );
wchar_t buf[1000];
while( fgetws(buf,999, fp ) ) {
fwprintf(L"%s",buf);
}
Если с выводом все в порядке, у вас есть файл UNICODE, если он искажен, это UTF-8
Если у вас есть UTF-8, вам придется конвертировать в Unicode, чтобы упростить обработку.
// convert UTF-8 to UNICODE
void String2WString( std::wstring& ws, const std::string& s )
{
ws.clear();
int nLenOfWideCharStr = MultiByteToWideChar(CP_ACP, 0,
s.c_str(), s.length(), NULL, 0);
PWSTR pWideCharStr = (PWSTR)HeapAlloc(GetProcessHeap(), 0,
nLenOfWideCharStr * sizeof(wchar_t)+2);
if (pWideCharStr == NULL)
return;
MultiByteToWideChar(CP_ACP, 0,
s.c_str(), s.length(),
pWideCharStr, nLenOfWideCharStr);
*(pWideCharStr+nLenOfWideCharStr ) = L'\0';
ws = pWideCharStr ;
HeapFree(GetProcessHeap(), 0, pWideCharStr);
}
// read UTF-8
FILE * fp = fopen( "fname","r" );
char buf[1000];
std::string aline;
std::wstring wline;
std::vector< std::wstring> vline;
while( fgets(buf,999, fp ) ) {
aline = buf;
String2WString( wline, aline );
vline.push_back( wline );
}
Выше предполагается, что вы находитесь в Windows. В Unix применяется та же идея, и код очень похож. Тем не менее, я не нахожу это настолько простым, поэтому я позволю эксперту UNIX предоставить подробности.