Лучший способ сканирования 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.