Delphi-提取标记之间的字符串(重复标记)

Delphi-提取标记之间的字符串(重复标记),delphi,Delphi,我正在尝试编写一个函数来提取两个标记之间的字符串。 问题是,第一个标记在该字符串中是重复的,并且计数未知,例如 Str := 'Delphi App Hello Hello SomeText here Hello Hello Hello This is a Test!'; 我想要的是extract你好,这是一个测试 TagF是最后一个问候词 TagL是测试 TagF的重复计数是随机的 Function sExtractBetweenTagsB(Const s, LastTag, First

我正在尝试编写一个函数来提取两个标记之间的字符串。 问题是,第一个标记在该字符串中是重复的,并且计数未知,例如

Str := 'Delphi App Hello Hello SomeText here Hello Hello Hello This is a Test!';
我想要的是extract你好,这是一个测试

  • TagF是最后一个问候词
  • TagL是测试
TagF的重复计数是随机的

Function sExtractBetweenTagsB(Const s, LastTag, FirstTag: string): string;
var
  i, f : integer;
  sTemp : string;
begin
  sTemp := s;
  repeat
    Delete(sTemp,Pos(FirstTag, sTemp),length(FirstTag));
  until AnsiPos(FirstTag,sTemp) = 0;
  f := Pos(LastTag, sTemp);
  Result:= FirstTag+' '+Copy(sTemp, 1, length(sTemp));
end;
输出为:

Hello Delphi App   SomeText here    This is a Test!
您可以使用该函数扫描字符串以查找标记并向前搜索:

program SO30827180;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  SysUtils,
  StrUtils;

function ExtractString(const Input : String; const TagF: String; const TagL : String) : String;

var
  LastPos : Integer;
  NewPos  : Integer;

begin
 Result := '';
 NewPos := Pos(TagF, Input);
 if NewPos <> 0 then
  begin
   LastPos := NewPos;
   // scan to last start tag
   while true do
    begin
     NewPos := PosEx(TagF, Input, NewPos+1);
     if NewPos <> 0 then
      LastPos := NewPos
     else
      Break;
    end;
   // now seek end tag, starting from last starting tag position
   NewPos := PosEx(TagL, Input, LastPos+1);
   if NewPos <> 0 then
    Result := Copy(Input, LastPos, NewPos-LastPos+Length(TagL));
  end;
end;

var
  Line : String;

begin
 Line := 'Delphi App Hello Hello SomeText here Hello Hello Hello This is a Test!';
 Writeln(Format('Input: "%s"', [Line]));
 Writeln(Format('Ouput: "%s"', [ExtractString(Line, 'Hello', 'Test!')]));
 Line := ' Test! Delphi App Hello Hello SomeText here Hello Hello Hello This is a Test! Some end chars';
 Writeln(Format('Input: "%s"', [Line]));
 Writeln(Format('Ouput: "%s"', [ExtractString(Line, 'Hello', 'Test!')]));
 Readln;
end.
输出:

Hello This is a Test

最简单的方法是使用正则表达式:

program Project1;

{$APPTYPE CONSOLE}

uses
  RegularExpressions;

var
  regEx : TRegEx;
  testString : string;
  m : TMatch;
begin
  testString := 'Delphi App Hello Hello SomeText here Hello Hello Hello This is a Test!';

  regEx := TRegEx.Create('(Hello(?!.*Hello).*?Test!)');
  m := regEx.Match(testString);

  if m.Success then
    WriteLn(m.Value)
  else
    WriteLn('No match.');
  ReadLn;
end.
这里是正则表达式

  • (你好(?!你好)
    --在字符串后面匹配“Hello”而不匹配“Hello”的实例(贪婪的前瞻)
  • *?
    --懒惰匹配任何东西
  • 测试!)
    --匹配“测试!”
如果您想概括:

function ExtractBetweenTags(const s : string; FirstTag, LastTag : string) : string;
var
  regEx : TRegEx;
begin
  regEx := TRegEx.Create(Format('(%s(?!.*%s).*?%s)', [FirstTag, FirstTag, LastTag]));
  result := regEx.Match(s).Value;
end;

尝试使用
lastdimiter
function@Mbo:虽然方便,但我宁愿使用32位的
PosEx
,因为它有一个快速代码优化,而
lastdimiter
没有。如果最后一个标记后面有第一个标记,则不起作用。@LURD嗯,要求不是很清楚,是吗?如果我正确理解了OP,则提取从最后一个起始标记开始。如果之后没有结束标记,那么结果应该是空的,不是吗?
program Project1;

{$APPTYPE CONSOLE}

uses
  RegularExpressions;

var
  regEx : TRegEx;
  testString : string;
  m : TMatch;
begin
  testString := 'Delphi App Hello Hello SomeText here Hello Hello Hello This is a Test!';

  regEx := TRegEx.Create('(Hello(?!.*Hello).*?Test!)');
  m := regEx.Match(testString);

  if m.Success then
    WriteLn(m.Value)
  else
    WriteLn('No match.');
  ReadLn;
end.
function ExtractBetweenTags(const s : string; FirstTag, LastTag : string) : string;
var
  regEx : TRegEx;
begin
  regEx := TRegEx.Create(Format('(%s(?!.*%s).*?%s)', [FirstTag, FirstTag, LastTag]));
  result := regEx.Match(s).Value;
end;