powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Помогите пожалуйста написать парсер для текстового файла
15 сообщений из 15, страница 1 из 1
Помогите пожалуйста написать парсер для текстового файла
    #39084506
Фотография Mandarin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
все привет! есть задача распарсить массив данных. Структура данных очень простая, это плоская таблица в которой строки разделены символом '\n' а колонки символом '\t'

вот пример
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
// читаем строку
wchar_t* ReadLn(wchar_t** DataRow){
 int p = UnicodeString(*DataRow).Pos('\n');
 wchar_t* r = UnicodeString(*DataRow).SubString(1,p-1).c_str();
 *DataRow = UnicodeString(*DataRow).Delete(1,p).c_str();
 return r;
}

// читаем колонку
wchar_t* ReadCol(wchar_t** Line) {
 int p = UnicodeString(*Line).Pos('\t');
 wchar_t* r = UnicodeString(*Line).SubString(1,p-1).c_str();
 *Line = UnicodeString(*Line).Delete(1,p).c_str();
 return r;
}

// ---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 // тестовый набор данных
 LPWSTR DataRow = L"r1col1\tr1col2\tr1col3\tr1col4\tr1col5\t\nr2col1\tr2col2\tr2col3\tr2col4\tr2col5\t\n";
// 
wchar_t* L1;
 while (UnicodeString(DataRow).Length() >0) {
  L1 = ReadLn(&DataRow);
  Memo1->Lines->Add(ReadCol(&L1));
  Memo1->Lines->Add(ReadCol(&L1));
  Memo1->Lines->Add(ReadCol(&L1));
  Memo1->Lines->Add(ReadCol(&L1));
  Memo1->Lines->Add(ReadCol(&L1));
 }
}



код рабочий но, что то мне подсказывает что не очень он оптимизирован, например мне не нравится то что переменные типа wchar_t в функциях ReadLn и ReadCol оборачиваются в UnicodeString, во вторых для чтения из буфера данных не обязательно его перестраивать постоянно для того чтобы в следующей итерации читать сначала буфера, а можно например читать X символов с N позиции.

вопрос: как оптимизировать чтение данных?
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39084573
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mandarin,
я не думаю, что здесь что-то надо о оптимизировать .
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39084593
egorych
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivMandarin,
я не думаю, что здесь что-то надо о оптимизировать .другое дело, что непонятно, задлянафига он использует эти все wchar_t и LPWSTR.

Mandarin, что мешает везде использовать UnicodeString?
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39084638
Фотография Mandarin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egorychMasterZivMandarin,
я не думаю, что здесь что-то надо о оптимизировать .другое дело, что непонятно, задлянафига он использует эти все wchar_t и LPWSTR.

Mandarin, что мешает везде использовать UnicodeString?

я как то раз проводил эксперимент по склеиванию строк wcscat() работало на порядки быстрее чем UnicodeString + UnicodeString, поэтому я для себя решил там где нужна скорость работаю с wchar_t там где нужно удобство с UnicodeString. Возможно я ошибаюсь.
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39084673
egorych
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mandarinтам где нужна скорость работаю с wchar_t там где нужно удобство с UnicodeString.имхо, тут главный тормоз - Memo1, поэтому как ты там распарсиваешь строки - совершенно всё равно.

PS а вообще, ты впадаешь в ересь преждевременной оптимизации )) пока профайлер не показывает где именно находится узкое место, имеет смысл писать понятный и читаемый код.
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39084756
Фотография Mandarin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egorychMandarinтам где нужна скорость работаю с wchar_t там где нужно удобство с UnicodeString.имхо, тут главный тормоз - Memo1, поэтому как ты там распарсиваешь строки - совершенно всё равно.

PS а вообще, ты впадаешь в ересь преждевременной оптимизации )) пока профайлер не показывает где именно находится узкое место, имеет смысл писать понятный и читаемый код.

Memo1 это только для примера, а что такое профайлер и с чем его едят? первый раз про него слышу у меня IDE C++ Builder XE10.
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39084758
Фотография Mandarin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mandarin,

P.S. оптимизация не бывает преждевременной :)
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39084775
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MandarinMandarin,
P.S. оптимизация не бывает преждевременной :)
Mandarinа что такое профайлер и с чем его едят?
Это, в частности, говорит о преждевременности оптимизации.
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39084979
Gsec
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Можно воспользоваться: CommaText

TButton
TStringGrid
TOpenTextFileDialog

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
void __fastcall TForm1::Button1Click(TObject *Sender) {
	TOpenTextFileDialog* openTxtDlg = new TOpenTextFileDialog(this);
	if (openTxtDlg->Execute(this->Handle)) {
		String filename = openTxtDlg->FileName;
		// Checking if the file exists
		if (FileExists(filename)) {
			TStringList* oFileStrings = new TStringList(this);
			TStringList* oRowColumns = new TStringList(this);

			oFileStrings->LoadFromFile(filename);
			StringGrid->RowCount = oFileStrings->Count;

			oRowColumns->Delimiter = '\t';
			int row = 0;
			int gridRow = 0;
			for (; row < oFileStrings->Count; row++) {
				oRowColumns->Clear();
				//!!!!!!!!!!!
				oRowColumns->CommaText = oFileStrings->Strings[row];
				//!!!!!!!!!!!
				oRowColumns->Insert(0, UnicodeString(gridRow));
				if (oRowColumns->Count > StringGrid->ColCount) {
					StringGrid->ColCount = oRowColumns->Count;
				}
				StringGrid->Rows[gridRow]->Assign(oRowColumns);
				gridRow++;
			}

			StringGrid->Cells[0][0] = "";
			oRowColumns->Clear();
			oRowColumns->Add("");
			for (int i = 1; i < StringGrid->ColCount; i++) {
				oRowColumns->Add(IntToHex(i, 2));
			}
			StringGrid->Rows[0]->Assign(oRowColumns);

			delete oFileStrings;
			delete oRowColumns;
		}
		else {
			MessageDlg("File does not exist", mtError,
				TMsgDlgButtons() << mbOK, 0);
		}
	}
	delete openTxtDlg;
}
// ---------------------------------------------------------------------------
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39085227
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Фейспалм.

Пусть уж лучше останется первая версия.
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39085291
Зимаргл
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
http://www.sbin.org/doc/HOWTO/C Programming-HOWTO-7.html

Надо сразу нормально писать код, это не относится к преждевременной оптимизации.
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39085329
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тут достаточно много примеров парсеров.

Только заменить запятую на табулятор.

http://stackoverflow.com/questions/1120140/how-can-i-read-and-parse-csv-files-in-c
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39088565
Пётр Седов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mandarin, чтобы разбирать (parse-ить) быстро, надо это делать без выделений памяти. Попробуйте так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
#include <wchar.h>

struct scan_context_t {
  const wchar_t* text; // не обязан завершаться нулём
  int text_len;
  int pos;
  int line_end;

  // результат scan_cell
  const wchar_t* cell; // не завершается нулём
  int cell_len;
};

void init_scan(scan_context_t* context, const wchar_t text[], int text_len = -1) {
  context->text = text;
  context->text_len = (text_len != -1 ? text_len : static_cast<int>(wcslen(text)));
  context->pos = 0;
}

bool begin_scan_row(scan_context_t* context) {
  const wchar_t* sep = wmemchr(context->text + context->pos, L'\n', context->text_len - context->pos);
  if (sep != NULL) {
    int sep_pos = sep - context->text;
    if ((sep_pos >= 1) && (context->text[sep_pos - 1] == L'\r')) // если '\r' перед '\n'
      context->line_end = sep_pos - 1; // не включаем '\r' в последнюю ячейку
    else
      context->line_end = sep_pos;
  } else {
    // последняя строка
    context->line_end = context->text_len;
  }
  // как только встретили пустую строку, завершаем разбор
  return context->pos < context->line_end;
}

void end_scan_row(scan_context_t* context) {
  int p = context->line_end;
  if ((p < context->text_len) && (context->text[p] == L'\r')) p++; // пропускаем '\r'
  if ((p < context->text_len) && (context->text[p] == L'\n')) p++; // пропускаем '\n'
  context->pos = p;
}

// результат -- в полях cell, cell_len
void scan_cell(scan_context_t* context) {
  context->cell = context->text + context->pos;
  const wchar_t* sep = wmemchr(context->text + context->pos, L'\t', context->line_end - context->pos);
  if (sep != NULL) {
    int sep_pos = sep - context->text;
    context->cell_len = sep_pos - context->pos;
    context->pos = sep_pos + 1; // пропускаем '\t'
  } else {
    // последняя ячейка в строке
    context->cell_len = context->line_end - context->pos;
    context->pos = context->line_end;
  }
}

...

void parse_table() {
  const wchar_t* const table = L"r1col1\tr1col2\tr1col3\tr1col4\tr1col5\t\nr2col1\tr2col2\tr2col3\tr2col4\tr2col5\t\n";

  scan_context_t sc;
  init_scan(&sc, table);

  while (begin_scan_row(&sc)) {
    scan_cell(&sc);
    Memo1->Lines->Add(UnicodeString(sc.cell, sc.cell_len));

    scan_cell(&sc);
    Memo1->Lines->Add(UnicodeString(sc.cell, sc.cell_len));

    scan_cell(&sc);
    Memo1->Lines->Add(UnicodeString(sc.cell, sc.cell_len));

    scan_cell(&sc);
    Memo1->Lines->Add(UnicodeString(sc.cell, sc.cell_len));

    scan_cell(&sc);
    Memo1->Lines->Add(UnicodeString(sc.cell, sc.cell_len));

    end_scan_row(&sc);
  }
}


P. S. 2015-ый год на дворе, а форум в C++-коде не раскрашивает синим «wchar_t», зато раскрашивает «Delete» (с большой буквы).
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39089446
ДохтаР
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пётр СедовP. S. 2015-ый год на дворе,

А мы изобретаем велосипеды
:)
...
Рейтинг: 0 / 0
Помогите пожалуйста написать парсер для текстового файла
    #39089461
Пётр Седов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ДохтаР, да, если при разборе допустимо менять содержимое буфера, то можно попробовать wcstok:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
void parse_table() {
  // копируем содержимое строкового литерала в локальный массив (потому что содержимое строкового литерала менять нельзя)
  wchar_t table[] = L"r1col1\tr1col2\tr1col3\tr1col4\tr1col5\t\nr2col1\tr2col2\tr2col3\tr2col4\tr2col5\t\n";
  const wchar_t* cell_1 = NULL;
  const wchar_t* cell_2 = NULL;
  const wchar_t* cell_3 = NULL;
  const wchar_t* cell_4 = NULL;
  const wchar_t* cell_5 = NULL;
  int cells_count = 0;
  // разбиваем текст на token-ы
  const wchar_t* seps = L"\t\r\n";
  for (wchar_t* tok = wcstok(table, seps); tok != NULL; tok = wcstok(NULL, seps)) {
    switch (cells_count) {
    case 0: cell_1 = tok; break;
    case 1: cell_2 = tok; break;
    case 2: cell_3 = tok; break;
    case 3: cell_4 = tok; break;
    case 4: cell_5 = tok; break;
    }
    cells_count++;
    if (cells_count == 5) {
      Memo1->Lines->Add(cell_1);
      Memo1->Lines->Add(cell_2);
      Memo1->Lines->Add(cell_3);
      Memo1->Lines->Add(cell_4);
      Memo1->Lines->Add(cell_5);
      cells_count = 0;
    }
  }
}
...
Рейтинг: 0 / 0
15 сообщений из 15, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Помогите пожалуйста написать парсер для текстового файла
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]