7

TPerlRegExクラスを使用して、スペースを新しい行に置き換えようとしています。

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

問題は、\ r\n置換をリテラルテキストとして扱うことです。

4

3 に答える 3

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.
于 2013-01-06T15:49:11.017 に答える
6

なぜ期待通りにマッチングしないのか、本当に知りたかったです。

テキスト\内のエスケープシーケンスの処理はで実行されます。コードを見ると、キャリッジリターンとラインフィードの文字を生成するシーケンスがないことがわかります。実際、すべてはバックリファレンスに関するものです。ReplacementTPerlRegEx.ComputeReplacementComputeReplacement

正規表現のマッチングフェーズの処理は、PCREコードによって実行されます。ただし、置換フェーズは純粋なPascalコードです。また、コードを調べてその機能を確認するのは簡単です。そして、それはあなたが考えていることや期待していることをしません。

結論として、エスケープシーケンスを使用して必要な文字を指定することはできません。OnReplace印刷できない文字をエスケープするための独自のルールを考案し、それらのルールをイベントハンドラーに適用する必要があると思います。

于 2013-01-06T18:00:25.803 に答える
1

今日、何か新しいことを学んだので、編集してください。

私はしばらく前の質問と同じ問題にぶつかり、間違った結論を出しました。
TRegExCスタイルのバックスラッシュエスケープ拡張はまったく行いません

正しい結論は、文字列パラメータでCスタイルのバックスラッシュエスケープ展開
TRegExを行わないということでした。文字列パラメータで行われるかどうかを調査する必要がありreplacementpatternます。

文字エスケープメカニズムのサポートは、開発ツールによって異なることを私は知っていました。

たとえば、C、C#、Java、Perl、PHP、Ruby、bashなど、バックスラッシュエスケープ拡張を実行します。
しかし、Delphiコンパイラ(Cスタイルのコンパイラではないため)はそうではありません。ただし、 Pascalスタイルのエスケープ( 、、または)をCRLF
に拡張します。#13#10^M^J

そこで、今日その調査を行い(最初の間違いを指摘してくれたDavidに感謝します)、基本的にこれを行う機能を持つ2つの例( 1つはDelphiで、もう1つはC#で)を考え出しました。

  • 既知のCRLF文字列のパターン一致結果と、文字列を含むパターンを表示します
  • スペースを文字列に置き換えることを示します

次に、サンプル関数は次のように呼び出されます。

  • ソースコードでバックスラッシュでエスケープされた文字列\r\ n文字列であるため、コンパイラによって解析される可能性があります
  • 文字をまとめてバックスラッシュでエスケープされた文字列\r\n文字列ランタイムはRegExエンジンによって解析される可能性があります

両方の例の出力から、次のことがわかります。

  • Delphiコンパイラは\r\n文字列を解析しません
  • C#コンパイラは\ r\n文字列を解析します
  • DelphiとC#の両方のRegExエンジンは、実行時にパターン文字列を解析します\ r \ n(RegEx ドキュメント
  • DelphiとC#の両方のRegExエンジンは、実行時に置換\ r \ n文字列を解析しません(RegEx ドキュメント

推奨されるスタイルは次のとおりです。

したがって、Pascalスタイルのエスケープを使用するか、Cosminが記述したようなCスタイルのバックスラッシュ拡張関数を使用します。

補足:拡張機能を使用する場合は、テキストの意味が変わることに注意してください。Delphiユーザーは、文字列のCスタイルの拡張を期待しない場合があります。

于 2013-01-07T08:22:09.817 に答える