如何使用 POS 搜索不同出现的字符串

How to search for different occurences of strings using POS

我正在尝试创建一个类似于 Delphi 的 pos 函数的函数,但我可以传递不同的字符串进行搜索,而不是只有一个。所以我可以这样调用函数:

multipos('word1#word2#word3','this is a sample text with word2',false); 
// will return 'word2'

函数会return找到哪个字符串。

我做的代码在下面,它可以工作,但是太慢了。我怎样才能提高这段代码的速度?

function multipos(needles,key: string; requireAll: boolean): string;
var
  k: array [1 .. 50] of string;
  i, j: integer;
  r, aux: string;
  flag: boolean;
begin
  if trim(key) = '' then
    Result := ''
  else
    try
      r := '';
      Result := '';
      j := 1;
      for i := 1 to 50 do
        k[i] := '';

      for i := 1 to length(needles) do
      begin
        if needles[i] <> '#' then
          aux := aux + needles[i]
        else
        begin
          k[j] := aux;
          Inc(j);
          aux := '';
        end;
        if j >= 50 then
          break;
      end;
      if aux <> '' then
        k[j] := aux;

      for i := 1 to j do
      begin
        if k[i] = '' then
          break
        else
          if pos(lowercase(k[i]), lowercase(key)) > 0 then
          begin
            if not requireAll then
            begin
              Result := k[i];
              break;
            end
            else
            begin
              r := r + k[i] + ',';
              flag := i = j;
              if not flag then
                flag := k[i + 1] = '';
              if flag then
              begin
                Result := r;
              end;
            end;
          end
          else
            if requireAll then
            begin
              break;
            end;
      end;
    except
      on e: exception do
      begin
        Result := '';
      end;
    end;
end;

考虑将项目作为数组传递,例如:

function Multipos(const A: array of string; const S: string): string;
begin
  for var E in A do
    if Pos(E, S) > 0 then
      Exit(E);
  Result := ''; // Nothing found
end;

// sample calls
Multipos(['word1', 'word2', 'word3'], 'sample text with word2');
Multipos('word1#word2#word3'.Split(['#']), 'sample text with word2');

要实现 RequireAll 功能,在第一次失败时停止。在这种情况下,只需检查 return 的内容即可。

此外,TStrings/TStringList 可以满足您的需求。检查它的 Delimiter 和 DelimitedText 属性。

Marcodor的数组解法不错。这是一个 TStringList 替代方案:

function multipos(SubStrs: TStringList; Str: string; RequireAll: Boolean): string;
var
  i: Integer;
begin
  if (not Str.IsEmpty) and (not SubStrs.Count < 1) then
  begin
    Result := '';
    for i := 0 to SubStrs.Count - 1 do
      if Pos(SubStrs[i], Str) > 0 then
        Result := Result + Copy(Str, Pos(SubStrs[i], Str), SubStrs[i].Length)
      else if RequireAll then
        Result := '';
  end;
end;

var
  myList: TStringList;

begin
  myList := TStringList.Create;
  myList.Delimiter := '#';
  myList.DelimitedText := 'word1#word2#word3';
  Writeln(multipos(myList, 'this word1is a sample word3 text with word2', False));
end.

显然您需要 system.classes 作为 StringList。也许在访问参数之前更好地检查是否一切正常,但它适用于 RequireAll True 和 False。

由于您没有指定 Delphi 版本,我假设是最新的:

function multipos(const needles,key: string; requireAll: boolean): string;
var
  lst: TStringList;
begin
  lst := TStringList.Create;
  try
    var lowerkey := key.ToLower; // do this only once
    for var needle in needles.Split(['#']) do begin
      if lowerkey.Contains(needle.ToLower) then begin
        if not requireAll then 
          Exit(needle);
        lst.Add(needle);
      end;
    end;
    Result := lst.CommaText;
  finally
    lst.Free;
  end;
end;