Разбор текстового файла UCS-2LE

У меня есть текстовый файл, который был создан с помощью некоторого инструмента отчетности Microsoft. Текстовый файл включает в себя BOM 0xFFFE в начале, а затем вывод ASCII символов с нулями между символами (т.е. "F.i.e.l.d.1."). Я могу использовать iconv, чтобы преобразовать это в UTF-8, используя UCS-2LE в качестве формата ввода и UTF-8 в качестве формата вывода... это прекрасно работает.

Моя проблема в том, что я хочу читать строки из файла UCS-2LE в строки и анализировать значения полей, а затем записывать их в текстовый файл ASCII (т.е. Field1 Field2). Я пробовал версии getline на основе string и wstring — пока он считывает строку из файла, такие функции, как substr(start, length), интерпретируют строку как значения 8-bit, поэтому значения начала и длины отключены.

Как прочитать данные UCS-2LE в строку C++ и извлечь значения данных? Я просмотрел boost и icu, а также многочисленные запросы в Google, но не нашел ничего подходящего. Что мне здесь не хватает? Пожалуйста помоги!

Мой примерный код выглядит так:

wifstream srcFile;
srcFile.open(argv[1], ios_base::in | ios_base::binary);
..
..
wstring  srcBuf;
..
..
while( getline(srcFile, srcBuf) )
{
    wstring field1;
    field1 = srcBuf.substr(12, 12);
    ...
    ...
}

Итак, если, например, srcBuf содержит "W.e. t.h.i.n.k. i.n. g.e.n.e.r.a.l.i.t.i.e.s.", то substr() выше возвращает ".k. i.n. g.e" вместо "g.e.n.e.r.a.l.i.t.i.e.s.".

Я хочу прочитать строку и обработать ее, не беспокоясь о многобайтовом представлении. Есть ли у кого-нибудь пример использования boost (или чего-то еще) для чтения этих строк из файла и преобразования их в представление с фиксированной шириной для внутреннего использования?

Кстати, я на Mac использую Eclipse и gcc. Возможно ли, что мой STL не понимает строки с широкими символами?

Спасибо!


person Cryptik    schedule 08.08.2009    source источник


Ответы (2)


У меня substr отлично работает в Linux с g++ 4.3.3. Программа

#include <string>
#include <iostream>

using namespace std;

int main()
{
  wstring s1 = L"Hello, world";
  wstring s2 = s1.substr(3,5);
  wcout << s2 << endl;
}

печатает "lo, w", как и должно быть.

Однако чтение файла, вероятно, делает что-то не то, что вы ожидаете. Он преобразует файлы из кодировки локали в wchar_t, в результате чего каждый байт становится собственным wchar_t. Я не думаю, что стандартная библиотека поддерживает чтение UTF-16 в wchar_t.

person Martin v. Löwis    schedule 09.08.2009
comment
Спасибо за ответ. Я вижу такое же поведение. Как вы сказали, я не думаю, что UTF-16 для wchar_t поддерживается. Я использовал iconv для преобразования файла в UFT-8, и это решило проблему. - person Cryptik; 23.08.2009
comment
Хотя я, вероятно, обращаюсь здесь к призракам, @Cryptik должен пометить свой вопрос как решенный :) - person Dr1Ku; 08.03.2013

Потратив несколько хороших часов на решение этого вопроса, вот мои выводы:

  • Чтение файла UTF-16 (или UCS2-LE), по-видимому, управляемо в С++ 11, см. Как записать строку в кодировке UTF-8 в файл в Windows на C++

  • Поскольку библиотека boost::locale теперь является частью C++11, можно просто использовать codecvt_utf16 (см. пулю ниже для возможных примеров кода)

  • Однако в более старых компиляторах (например, MSVC 2008) вы можете использовать locale и пользовательский codecvt аспект/"рецепт", как очень хорошо показано в этот ответ на Запись UTF16 в файл в двоичном режиме

  • В качестве альтернативы можно также попробовать это способ чтения, хотя в моем случае он не сработал. На выходе будут отсутствующие строки, которые будут заменены символами мусора.

Я не смог сделать это в моем компиляторе до С++ 11, и мне пришлось прибегнуть к написанию сценария на Ruby и созданию процесса (он просто тестируется, поэтому я думаю, что такие сложности там в порядке) для выполнения моего задача.

Надеюсь, что это сэкономит время другим, рад помочь.

person Dr1Ku    schedule 13.03.2013