如何检查字符串是否包含子字符串,但仅在特定位置?
示例字符串:
您的最喜欢的颜色是什么?我的[最喜欢的]颜色为蓝色
如果我想检查字符串是否包含特定单词,我通常会这样做:
var
S: string;
begin
S := 'What is your favorite color? my [favorite] color is blue';
if (Pos('favorite', S) > 0) then
begin
//
end;
end;
我需要确定字符串中是否存在收藏夹这个词,忽略它是否出现在[]符号中,上面的代码示例显然没有这样做。
因此,如果我们将代码放入布尔函数中,一些示例结果将如下所示:
TRUE:你的最喜欢的颜色是什么?我的[我最喜欢的]颜色为蓝色
TRUE:你的最喜欢的颜色是什么?我的[ blah blah ]颜色为蓝色
FALSE:你的 blah blah 颜色是什么?我的[某些喜欢的]颜色为蓝色
上面的前两个样本都是真的,因为在[]符号之外找到了收藏词,无论它是否在其中。
第三个样本是假的,因为即使有喜欢这个词,它也只出现在[]符号内 - 我们应该只检查它是否存在于符号之外。
所以我需要一个函数来确定一个单词(在这个例子中是最喜欢的)是否出现在一个字符串中,但忽略了这个单词被包含在[]符号中的事实。
答案 0 :(得分:8)
我喜欢Sertac's idea
关于删除括号括起来的字符串并在此之后搜索字符串。以下是通过搜索整个单词和区分大小写扩展的代码示例:
function ContainsWord(const AText, AWord: string; AWholeWord: Boolean = True;
ACaseSensitive: Boolean = False): Boolean;
var
S: string;
BracketEnd: Integer;
BracketStart: Integer;
SearchOptions: TStringSearchOptions;
begin
S := AText;
BracketEnd := Pos(']', S);
BracketStart := Pos('[', S);
while (BracketStart > 0) and (BracketEnd > 0) do
begin
Delete(S, BracketStart, BracketEnd - BracketStart + 1);
BracketEnd := Pos(']', S);
BracketStart := Pos('[', S);
end;
SearchOptions := [soDown];
if AWholeWord then
Include(SearchOptions, soWholeWord);
if ACaseSensitive then
Include(SearchOptions, soMatchCase);
Result := Assigned(SearchBuf(PChar(S), StrLen(PChar(S)), 0, 0, AWord,
SearchOptions));
end;
这是函数的优化版本,它使用指针字符迭代而不进行字符串操作。与以前的版本相比,当你有一个缺少结束括号的字符串时就会处理这种情况,例如My [favorite color is
。由于缺少括号,这样的字符串被评估为True。
原则是通过char遍历整个字符串char,当找到左括号时,查看该括号是否有自己的结束对。如果是,则检查存储位置的子字符串是否包含搜索的单词。如果是,请退出该功能。如果不是,请将存储的位置移动到右括号。如果左括号没有自己的闭合对,则从存储位置搜索单词到整个字符串的末尾并退出该函数。
此代码的评论版follow this link 。
function ContainsWord(const AText, AWord: string; AWholeWord: Boolean = True;
ACaseSensitive: Boolean = False): Boolean;
var
CurrChr: PChar;
TokenChr: PChar;
TokenLen: Integer;
SubstrChr: PChar;
SubstrLen: Integer;
SearchOptions: TStringSearchOptions;
begin
Result := False;
if (Length(AText) = 0) or (Length(AWord) = 0) then
Exit;
SearchOptions := [soDown];
if AWholeWord then
Include(SearchOptions, soWholeWord);
if ACaseSensitive then
Include(SearchOptions, soMatchCase);
CurrChr := PChar(AText);
SubstrChr := CurrChr;
SubstrLen := 0;
while CurrChr^ <> #0 do
begin
if CurrChr^ = '[' then
begin
TokenChr := CurrChr;
TokenLen := 0;
while (TokenChr^ <> #0) and (TokenChr^ <> ']') do
begin
Inc(TokenChr);
Inc(TokenLen);
end;
if TokenChr^ = #0 then
SubstrLen := SubstrLen + TokenLen;
Result := Assigned(SearchBuf(SubstrChr, SubstrLen, 0, 0, AWord,
SearchOptions));
if Result or (TokenChr^ = #0) then
Exit;
CurrChr := TokenChr;
SubstrChr := CurrChr;
SubstrLen := 0;
end
else
begin
Inc(CurrChr);
Inc(SubstrLen);
end;
end;
Result := Assigned(SearchBuf(SubstrChr, SubstrLen, 0, 0, AWord,
SearchOptions));
end;
答案 1 :(得分:7)
在regular expressions中,您可以使用名为look-around的内容。在你的情况下,你可以用负面的lookbehind解决它:你想要“最喜欢的”,除非它之前有一个开放括号。它看起来像这样:
(?<!\[[^\[\]]*)favorite
一步一步:(?<!
是负面的lookbehind前缀,我们正在寻找\[
,可选地后面跟着没有关闭或打开括号的所有内容:[^\[\]]*
,关闭)
的负面背后隐藏,然后是favorite
。
答案 2 :(得分:0)
我认为你可以将你的问题改为“找到所提供的字符串不被方括号包围的事件”。如果这描述了您的问题,那么您可以继续使用简单的正则表达式,例如[^\[]favorite[^\]]
。