如何在分隔符后提取子字符串,但如果在两个标记之间找到则忽略它?

时间:2016-10-22 16:27:24

标签: delphi lazarus

我需要在特定分隔符后提取子字符串,但如果指定的分隔符位于其他两个标记之间,则应忽略它。

例如,拿这个测试字符串:

  

快速<“@ brown fox”>跳过懒狗。快速的@ 棕色狐狸   跳过懒狗

所需的输出是:

  

棕色狐狸跳过懒狗

这是因为第一个找到@分隔符在两个“”之间,因此应该被忽略,第二个@分隔符不在“”内部,因此之后的文本应该被提取。

我可以使用Pos找到@ delimiter的起始位置,然后将文本提取到右侧,如下所示:

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
  I: Integer;
begin
  S := 'The quick <"@brown fox"> jumps over the lazy dog. The quick @brown fox jumps over the lazy dog';
  I := Pos('@', S);
  if I > 0 then
  begin
    ShowMessage(Copy(S, I, Length(S)));
  end;
end;

然而,无论是否包含两个“”,它总是会找到第一个@分隔符。以上结果是:

  

@brown fox“&gt;跳过懒狗。快速的@ 棕色狐狸跳过   懒狗

所需的结果应该是:

  

棕色狐狸跳过懒狗

如果分隔符位于两个“”标记之间,如何在使用Pos时更改代码以忽略@分隔符?我只想找到第一个@分界符,然后复制文本。

在找到第一个有效的@分隔符之后是否还有其他@分隔符也没关系,例如这也应该是有效的:

  

快速&lt;“@ brown fox”&gt;跳过懒狗。快速的@ 棕色狐狸   跳跃@ ov @ er lazy @ dog

仍应返回:

  

棕色狐狸跳过懒狗

因为我们只对第一个有效的@分隔符感兴趣,之后忽略其他任何内容并忽略两个“”标记之间的任何内容。

请注意,虽然我已经标记了Delphi,但我确实主要使用Lazarus,所以我需要帮助提出一个不使用魔术帮助的解决方案,如字符串助手等。

感谢。

2 个答案:

答案 0 :(得分:1)

要查明@是否不在"个封闭标记内,请从头开始解析字符串。

如果在开始标记之后找到分隔符,但没有结束标记,则此例程也将提取结果。

function ExtractString(const s: String): String;
var
  tagOpen: Boolean;
  delimiterPos,i,j: Integer;
begin
  tagOpen := false;
  delimiterPos := 0;
  Result := '';
  for i := 1 to Length(s) do begin
    if (s[i] = '"') then begin
      tagOpen := not tagOpen;
      delimiterPos := 0;
    end
    else begin
      if (s[i] = '@') then begin
        if (delimiterPos = 0) then
          delimiterPos := i;
        if not tagOpen then // Found answer
          Break;
      end;
    end;         
  end;

  // If there is no closing tag and a delimiter is found
  // since the last opening tag, deliver a result. 
  if (delimiterPos > 0) then begin
    // Finally extract the string and remove all `@` delimiters.
    SetLength(Result,Length(s)-delimiterPos);
    j := 0;
    for i := 1 to Length(Result) do begin
      Inc(delimiterPos);
      if (s[delimiterPos] <> '@') then begin
        Inc(j);
        Result[j] := s[delimiterPos];
      end;
    end;
    SetLength(Result,j);      
  end;
end;

答案 1 :(得分:0)

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
  L, I: Integer;
  take : Boolean;
begin
  S := 'The quick <"@brown fox"> jumps over the lazy dog. The quick @brown fox jumps over the lazy dog';
  L := Length(S);
  I := Pos('@', S);

  while I > 0 do
  begin
    take := True;
    if I > 1 then take := S[I-1] <> '"';
    if take then begin
      if I < L then
        ShowMessage(Copy(S, I + 1, L));
      Break;
    end;
    S[I] := '_';
    I := Pos('@', S);
  end;
end;