当指定为替换时,为什么TPerlRegEx未正确处理回车换行(CR LF)

时间:2013-01-06 15:40:33

标签: delphi

我尝试使用TPerlRegEx类用新行替换空格。

with RegExp do
begin
  Subject:=Memo1.Lines.Text;
  RegEx:=' ';
  Replacement:='\r\n';
  ReplaceAll;
  Memo1.Lines.Text:=Subject;
end;

问题在于它将\ r \ n替换视为文字文本。

3 个答案:

答案 0 :(得分:8)

使用#13#10

program Project29;

{$APPTYPE CONSOLE}

uses
  SysUtils, PerlRegEx;

var RegEx: TPerlRegEx;

function CStyleEscapes(const InputText:string):string;
var i,j: Integer;

begin
  SetLength(Result, Length(InputText));
  i := 1; // input cursor
  j := 1; // output cursor
  while i <= Length(InputText) do
    if InputText[i] = '\' then
      if i = Length(InputText) then
        begin
          // Eroneous quotation...
          Result[j] := '\';
          Inc(i);
          Inc(j);
        end
      else
        begin
          case InputText[i+1] of
            'r', 'R': Result[j] := #13;
            'n', 'N': Result[j] := #10;
            't', 'T': Result[j] := #9;
            '\':
              begin
                Result[j] := '\';
                Inc(j);
                Result[j] := '\';
              end;
            else
              begin
                Result[j] := '\';
                Inc(j);
                Result[j] := InputText[i+1];
              end;
          end;
          Inc(i,2);
          Inc(j);
        end
    else
      begin
        Result[j] := InputText[i];
        Inc(i);
        Inc(j);
      end;
  SetLength(Result, j-1);
end;

begin
  RegEx := TPerlRegEx.Create;
  try

    RegEx.RegEx := ' ';
    RegEx.Replacement := CStyleEscapes('\t\t\t');;
    RegEx.Subject := 'FirstLine SecondLine';
    RegEx.ReplaceAll;
    WriteLn(RegEx.Subject);

    ReadLn;

  finally RegEx.Free;
  end;
end.

答案 1 :(得分:6)

  

我真的很想知道它为什么不按预期进行匹配。

\文本中Replacement转义序列的处理在TPerlRegEx.ComputeReplacement中执行。如果您查看代码,您会发现没有产生回车符和换行符的序列。事实上,ComputeReplacement完全是关于后向引用。

正则表达式的匹配阶段的处理由PCRE代码执行。但是,替换阶段是纯粹的Pascal代码。并且很容易检查代码以查看它的作用。它并没有按照你的想法做到并期望它做到。

结论是您无法使用转义序列指定所需的字符。我认为您需要设计自己的规则来转义不可打印的字符,并在OnReplace事件处理程序中应用这些规则。

答案 2 :(得分:1)

编辑,因为我今天学到了新东西。

我遇到了与前一段时间相同的问题,并得出了错误的结论 TRegEx根本不做任何C风格的backslash escape expansion

正确的结论应该是这样的 TRegEx不会在replacement字符串参数中执行C风格backslash escape expansion,我应该研究它是否在pattern字符串参数中。

我知道支持角色转义机制varies by development tool

例如,C,C#,Java,Perl,PHP,Ruby,bash等等都做反斜杠转义扩展。
但是由于Delphi编译器(因为它不是C风格的编译器)没有 它会将Pascal-style escapes(例如#13#10^M^J)扩展为CRLF。

所以今天我做了那个研究(感谢David指出我最初的错误),并提出了两个例子(one in Delphione in C#),它们的功能基本上是这样的:< / p>

  • 显示已知CRLF字符串的模式匹配结果,以及包含字符串
  • 的模式
  • 显示用字符串替换空格

然后通过以下方式调用示例函数:

  • 源代码中的字符串是反斜杠转义\ r \ n字符串,因此可能会被编译器解析
  • 一个字符串,它被放在一起,因此它成为一个反斜杠转义\ r \ n字符串运行时它可能会被RegEx引擎解析

从两个示例的输出中,您可以看到:

  • Delphi编译器不解析\ r \ n字符串
  • C#编译器会解析\ r \ n字符串
  • Delphi和C#中的RegEx引擎在运行时解析模式\ r \ n字符串(RegEx documentation
  • Delphi和C#中的RegEx引擎都不会在运行时解析replace \ r \ n字符串(RegEx documentation

建议stil代表:

因此要么使用Pascal式转义,要么使用像C-Style backslash expansion function这样的Cosmin写的。

作为旁注:当使用任何扩展功能时,您应该记住它会改变文本的含义。 Delphi用户可能不希望C字符串扩展字符串。