【发布时间】:2021-05-22 17:41:30
【问题描述】:
Delphi (10.4) 是否有一个 string-tokenizer,可以以类似于下面的方式从字符串中提取 string-token-objects?
MyPhrase := 'I have a simple word and a complex Word: A lot of WORDS.';
MyTokens := MyTokenize(MyPhrase, 'word');
for i := 0 to MyTokens.Count - 1 do
Memo1.Lines.Add(IntToStr(MyTokens[i].Pos) + ': ' + MyTokens[i].String);
在 Memo1 中给出这个结果:
16: word
35: Word
50: WORD
在 Delphi 文档中搜索“tokenize string”并没有得到任何有用的结果。
当然,写这样一个函数是小菜一碟,但不知道现有庞大的Delphi代码宝库中是否已经有这个程序。
编辑:我正在试验一个应该具有所需功能的单词表:
program MyTokenize;
{$APPTYPE CONSOLE}
{$R *.res}
uses
CodeSiteLogging,
System.RegularExpressions,
System.Types,
System.Classes,
System.StrUtils,
System.SysUtils;
type
PWordRec = ^TWordRec;
TWordRec = record
WordStr: string;
WordPos: Integer;
end;
TWordList = class(TList)
private
function Get(Index: Integer): PWordRec;
public
destructor Destroy; override;
function Add(Value: PWordRec): Integer;
property Items[Index: Integer]: PWordRec read Get; default;
end;
function TWordList.Add(Value: PWordRec): Integer;
begin
Result := inherited Add(Value);
end;
destructor TWordList.Destroy;
var
i: Integer;
begin
for i := 0 to Count - 1 do
FreeMem(Items[i]);
inherited;
end;
function TWordList.Get(Index: Integer): PWordRec;
begin
Result := PWordRec(inherited Get(Index));
end;
var
WordList: TWordList;
WordRec: PWordRec;
i: Integer;
begin
try
//MyPhrase := 'A crossword contains words but not WORD';
WordList := TWordList.Create;
try
// AV only at the THIRD loop!!!
for i := 0 to 2 do
begin
GetMem(WordRec, SizeOf(TWordRec));
WordRec.WordPos := i;
WordRec.WordStr := IntToStr(i);
WordList.Add(WordRec);
end;
for i := 0 to WordList.Count - 1 do
Writeln('WordPos: ', WordList[i].WordPos, ' WordStr: ', WordList[i].WordStr);
WriteLn(' Press Enter to free the list');
ReadLn;
finally
WordList.Free;
end;
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
ReadLn;
end;
end;
end.
不幸的是,它有一个奇怪的错误:它恰好在第三个 for 循环中获得了一个 AV!
EDIT2:似乎只有在项目的构建配置设置为Debug 时才会发生 AV。当项目的 Build Configuration 设置为 Release 时,就没有 AV。这和 MemoryManager 有关系吗?
【问题讨论】:
-
@user1580348:请注意我没有投反对票。根据我对 SO 社区的了解,我只是在猜测其他人为什么这样做。无需杀死信使。
-
我同意,这是一个有效的问题。只是说这种解释对每个人来说可能并不明显。但是有了你在这里的评论,它确实变得很明显。您可能希望在下次 Q 中包含“当然,编写这样的函数是微不足道的,但我想知道 Delphi RTL 中是否已经有一个标准工具”或类似的东西。关于“填字游戏”,我可能会警告您,有数学倾向的人不会认为示例可以替代精确的说明。
-
“从我的例子中,很明显它应该产生 (14, word)” 我的理解正好相反。
-
在通常的规则下,分词会将“填字游戏”视为单个词,因此无法匹配“单词”。在这里使用术语“令牌”是不正确的。看来您要做的就是在字符串中查找子字符串的出现(以不区分大小写的方式)。
-
代码中发生的情况是,在
GetMem之后,WordRec指向内存中新分配的SizeOf(TWordRec)大小的区域。由于GetMem没有用零填充这个块,WordRec.WordStr将是一个随机指针。因此,当您执行WordRec.WordStr := '...'时,RTL 将转到内存中的这个随机位置,认为它是一个字符串堆对象,并将其“引用计数”减少 1。换句话说,它将进行“随机”更改到内存中的“随机”位置。那么任何事情都可能发生。希望是 AV。
标签: string delphi tokenize delphi-10.4-sydney