我正在寻找有关如何使用Delphi 7最好地处理编程任务的建议。
我需要能够快速识别CSV文件中的值(大小小于15kb)。 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)数据量不是很大(CSV文件中有1500行,即1500段),2)数据库引擎的额外开销(我只需要读取数据,而不是写入数据),3)从程序中调用此函数的频率。
你会推荐什么,为什么?
答案 0 :(得分:3)
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.
如果Delphi 7在StrUtils中没有PosEx函数,您可以按如下方式编写代码:
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;
答案 1 :(得分:2)
为什么不使用TStrings的可能鲜为人知的CommaText属性而不是编写自己的代码?
使用CommaText的示例如下所示。 CODE
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;
将显示引用:a b c,d
作为三个ShowMessage调用的输出。
安德鲁
英国汉普郡
答案 2 :(得分:1)
如果文件不是那么大(〜几千字节),我建议将其读入内存,并搜索#13#10','。此字符串后面的下一个数字将是您要搜索的数字(当然,如果您的文件中没有多余的空格)。
答案 3 :(得分:1)
我想我会创建二维数组
Book[Chapter, Paragraph]
并通过阅读文件手动填写。
这个功能很简单:
GetNumberOfPages(Chapter: integer; Paragraph: integer): integer;
begin
Result := Book[Chapter, Paragraph];
end;
如果您正在寻找第三方工具,JEDi可以选择
答案 4 :(得分:0)
使用2dim数组,您需要一个stringlist helper作为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