Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Помогите пожалуйста написать парсер для текстового файла / 15 сообщений из 15, страница 1 из 1
23.10.2015, 12:06
    #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
23.10.2015, 12:34
    #39084573
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите пожалуйста написать парсер для текстового файла
Mandarin,
я не думаю, что здесь что-то надо о оптимизировать .
...
Рейтинг: 0 / 0
23.10.2015, 12:44
    #39084593
egorych
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите пожалуйста написать парсер для текстового файла
MasterZivMandarin,
я не думаю, что здесь что-то надо о оптимизировать .другое дело, что непонятно, задлянафига он использует эти все wchar_t и LPWSTR.

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

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

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

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

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

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

P.S. оптимизация не бывает преждевременной :)
...
Рейтинг: 0 / 0
23.10.2015, 14:15
    #39084775
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите пожалуйста написать парсер для текстового файла
MandarinMandarin,
P.S. оптимизация не бывает преждевременной :)
Mandarinа что такое профайлер и с чем его едят?
Это, в частности, говорит о преждевременности оптимизации.
...
Рейтинг: 0 / 0
23.10.2015, 15:43
    #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
23.10.2015, 17:48
    #39085227
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите пожалуйста написать парсер для текстового файла
Фейспалм.

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

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

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

http://stackoverflow.com/questions/1120140/how-can-i-read-and-parse-csv-files-in-c
...
Рейтинг: 0 / 0
28.10.2015, 04:08
    #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
29.10.2015, 01:25
    #39089446
ДохтаР
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите пожалуйста написать парсер для текстового файла
Пётр СедовP. S. 2015-ый год на дворе,

А мы изобретаем велосипеды
:)
...
Рейтинг: 0 / 0
29.10.2015, 02:44
    #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
Форумы / C++ [игнор отключен] [закрыт для гостей] / Помогите пожалуйста написать парсер для текстового файла / 15 сообщений из 15, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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