Лучший способ сканирования CSV файла для значения в Delphi 7

Я ищу советы о том, как лучше всего выполнять задачу программирования с помощью Delphi 7.

Мне нужно иметь возможность быстро идентифицировать значение из файла CSV (размером менее 15 КБ). Файл CSV существует в формате:

Номер главы, номер абзаца, общее количество слов в параграфе

Я хочу получить это последнее значение, т.е. Количество слов, предоставив функции первые два значения (т.е. Номер главы и параграфа).

Файл CSV сортируется численно, то есть:

1,1,30 // first paragraph of first chapter (line # 1)
1,2,56 // second paragraph of first chapter (line # 2)
1,3,101
1,4,56
...
2,1,78
2,2,51
...
100,1,87
100,2,101
...
100,23,78 // last paragraph of last chapter (line # 1500)

Поэтому в приведенном выше примере я хотел бы передать 2,2 функции и вернуть ей "51" (целое число)

Я бы хотел избежать использования таблицы базы данных, потому что: 1) объем данных не такой большой (1500 строк в файле CSV, т.е. 1500 абзацев), 2) дополнительные накладные расходы на механизм базы данных (мне нужно только для чтения данных, а не для записи данных), 3) частота, с которой эта функция будет вызываться из программы.

Что бы вы порекомендовали и почему?

5 ответов

TYPE TTwoDimIntArr = ARRAY OF ARRAY OF Cardinal;
PROCEDURE SetValue(VAR ARR : TTwoDimIntArr ; Chapter,Paragraph,Value : Cardinal); BEGIN IF Chapter>=LENGTH(ARR) THEN SetLength(ARR,SUCC(Chapter)); IF Paragraph>=LENGTH(ARR[Chapter]) THEN SetLength(ARR[Chapter],SUCC(Paragraph)); ARR[Chapter,Paragraph]:=Value END;
FUNCTION GetValue(CONST ARR : TTwoDimIntArr ; Chapter,Paragraph : Cardinal) : Cardinal; BEGIN IF Chapter>=LENGTH(ARR) THEN Result:=0 ELSE IF Paragraph>=LENGTH(ARR[Chapter]) THEN Result:=0 ELSE Result:=ARR[Chapter,Paragraph] END;
FUNCTION ParseFile(CONST FileName : STRING) : TTwoDimIntArr; VAR SL : TStrings; S : STRING; P,Q : Cardinal; {$IFDEF DELPHI7 } I : Cardinal; {$ENDIF } BEGIN SL:=TStringList.Create; TRY SL.LoadFromFile(FileName); {$IFDEF DELPHI7 } FOR I:=1 TO SL.Count DO BEGIN S:=SL[PRED(I)]; {$ELSE } FOR S IN SL DO BEGIN {$ENDIF } P:=POS(',',S); Q:=PosEx(',',S,SUCC(P)); SetValue(Result,StrToInt(COPY(S,1,PRED(P))),StrToInt(COPY(S,SUCC(P),PRED(Q-P))),StrToInt(COPY(S,SUCC(Q),255))) END FINALLY SL.Free END END;

ParseFile анализирует файл и возвращает его в двумерном динамическом массиве. Если вы на 100% уверены, что не превышаете границы массива, вы можете получить к нему доступ напрямую. В противном случае функция GetValue является безопасной оболочкой для доступа к содержимому массива.

Используйте его как:

USES ... StrUtils ...;
.
.<my code="">
.
VAR ARR : TTwoDimIntArr;
BEGIN ARR:=ParseFile(<filename>); . . . Words:=GetValue(ARR, <chapter>, <paragraph>); . .
END.
</paragraph></chapter></filename></my>

Если Delphi 7 не имеет функции PosEx в StrUtils, вы можете запрограммировать ее следующим образом:

FUNCTION PosEx(CONST SearchFor,SearchIn : STRING ; StartPos : Cardinal = 1) : Cardinal; BEGIN Result:=POS(SearchFor,COPY(SearchIn,StartPos,$7FFFFFFF)); IF Result>0 THEN INC(Result,PRED(StartPos)) END;


Вместо написания собственного кода, почему бы не использовать, возможно, малоизвестное свойство CommaText для TStrings?

Ниже приведен пример использования CommaText. КОД

var s: TStringList;
begin s := TStringList.Create; try s.CommaText := 'a, b, "c,d"'; ShowMessage( s[0] ); ShowMessage( s[1] ); ShowMessage( s[2] ); finally s.Free; end;
end;

Показать Цитата: abc, d

как вывод трех вызовов ShowMessage.

Андрей

Хэмпшир, Великобритания


С массивом 2dim вам нужен помощник stringlist как temp:

BEGIN SL:=TStringList.Create; sltemp:= TStringList.Create; TRY SL.LoadFromFile(FileName); writeln('Scikit Boston Samples: '+itoa(sl.count-1)) FOR I:= 0 TO SL.Count-1 DO BEGIN S:=SL[(I)]; SLtemp.CommaText:= S; for sll:= start-1 to col-1 do SetValue(Result,I,Sll,StrToFloat(sltemp[sll])) END; FINALLY sltemp.free; SL.Free END


Если файл не такой большой (~ несколько килобайт), я бы рекомендовал его прочитать в памяти и найти # 13 # 10 ','. Следующий номер после этой строки будет номером, который вы ищете (конечно, если в вашем файле нет лишних пробелов).


Я думаю, я бы создал двумерный массив

Book[Chapter, Paragraph]

и заполните его вручную, прочитав файл.

И функция будет тривиальной:

GetNumberOfPages(Chapter: integer; Paragraph: integer): integer;
begin Result := Book[Chapter, Paragraph];
end;

Если вы ищете 3-х партийные инструменты, JEDi может выбрать вариант

http://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvCsvDataSet

licensed under cc by-sa 3.0 with attribution.