トップページに戻る    次のSQLパズルへ    前のSQLパズルへ

10-203 正規表現の否定先読みを代用

SQLパズル

beforeデータ
---------------------------------------------------
fred this winfred freddies is fred fred record fred
fred fred freddies freddies
fred fred freddy freddies

単語のfredをfreddiesに置換する。

出力結果
-----------------------------------------------------------------------------
before***fred this winfred freddies is fred fred record fred
after****freddies this winfred freddies is freddies freddies record freddies
before***fred fred freddies freddies
after****freddies freddies freddies freddies
before***fred fred freddy freddies
after****freddies freddies freddy freddies

こちらを参考にさせていただきました(英語)


SQL

declare
    procedure fred_To_freddies(pstr varchar2) is
        willReturn varchar2(4000);
    begin
        DBMS_Output.Put_Line('before***' || pstr);
        willReturn := pstr;
        for i in 1..length(pstr)*2 Loop
      --for i in 1..length(pstr)*length('freddies')/length('fred') Loop
            --willReturn := RegExp_Replace(willReturn, '(^| )fred(dies)?( |$)', '\1freddies\3',i);
            willReturn := RegExp_Replace(willReturn, '(^| )fred( |$)', '\1freddies\2',i);
        end Loop;
        DBMS_Output.Put_Line('after****' || willReturn);
    end;
begin
    fred_To_freddies('fred this winfred freddies is fred fred record fred');
    fred_To_freddies('fred fred freddies freddies');
    fred_To_freddies('fred fred freddy freddies');
end;
/


解説

Oracleの正規表現は、11gでも先読みと戻り読みがサポートされてないので、
キャプチャしつつマッチさせて後方参照という方法を使う必要があります。

EmEditorの正規表現なら
((?<=^)|(?<= ))fred(?= |$)
を
freddies
に置換
すればいいです。

■■■■■■■■■■■■■■■■■■■■■■■■■■
RegExp_Replace関数は、
第4引数を指定しても
行頭とみなす位置は変わらないようです。

SQL> select RegExp_Replace('abc','^bc','ZZZ',1) as a,
  2  RegExp_Replace('abc','^bc','ZZZ',2) as b,
  3  RegExp_Replace('abc','^bc','ZZZ',3) as c,
  4  RegExp_Replace('abc','^bc','ZZZ',4) as d,
  5  RegExp_Replace('abc','^bc','ZZZ',5) as e
  6    from dual;

A    B    C    D    E
---  ---  ---  ---  ---
abc  abc  abc  abc  abc