2016-08-24 11 views
0

文字列を編集したいと思います。近くの2桁の数字と文字(00→0a、01-0b、23-2cなど)
111324→1b1d2eから取得します。 はその後、私のコード:Oracle。無効な正規表現の結果のASCII値

set serveroutput on size unlimited 

declare 
    str varchar2(128); 

    function convr(num varchar2) return varchar2 is 
    begin 
    return chr(ascii(num)+49); 
    -- return chr(ascii(num)+49)||'<-'||(ascii(num)+49)||','||ascii(num)||','||num||'|'; 
    end; 

    function replace_dd(str varchar2) return varchar2 is 
    begin 
    return regexp_replace(str,'((\d)(\d))','\2'||convr('\3')); 
    end; 
begin 
    str := '111324'; 
    Dbms_Output.Put_Line(str); 
    Dbms_Output.Put_Line(replace_dd(str)); 
end; 

しかし、私は次の文字列を取得 '112'。私はI'vが得たコメント返される文字列で結果を確認し

: '| 1 < -141,92,3 | 1 < -141,92,1を2 < -141,92,4 |'。

ascii(num)はnumに依存しません。それは常にascii( '\')のように動作します。それは92で、さらに49で141を得て、それはアスキーテーブルから出ています。しかし、それだけでnumは正しく印刷されます。 正しい値を取得するにはどうすればよいですか?または、この問題を解決する別の方法ですか?

+0

私が手に '<-141,92、3 \ |'コメントアウト行から。あなたが期待している後方参照ではなく、文字 '\ 3 'が渡されているようです。 ''は '' regexp_replace(str、 '((\ d)(\ d))'、 '\ 2') 'から取得したもので、' convr'は印刷できないものがあります。 –

+0

@AlexPooleどのようにconvr()に正しい値を送るか? –

+0

これは不可能です。 'FOR i IN 1. INLAY(str)LOOP ...'のみです。 – Mike

答えて

-1

ここでのコードは、単一の文字に5を追加し、isssueを解決:このような何か(プレーンSQLで行うには、あなたが好きなら、あなたの関数にそれを書き換えることができます)。

set serveroutput on size unlimited 

declare 
    str varchar2(128); 
    str1 varchar2(128); 
    function replace_a(str varchar2) return varchar2 is 
    begin 
    return regexp_replace(str,'(\D)','5\1'); 
    end; 

    function convr(str varchar2) return varchar2 is 
    ind number; 
    ret varchar2(128); 
    begin 
    Dbms_Output.Put_Line(str); 
    --return chr(ascii(num)+49)||'<-'||(ascii(num)+49)||','||ascii(num)||','||num||'|'; 
    ind := 1 ; 
    ret :=str; 
    loop 
    ind := regexp_instr(':'||ret,'(#\d#)',ind) ; 
    exit when ind=0; 
    Dbms_Output.Put_Line(ind); 
    ret := substr(ret,1,ind-2)||chr(ascii(substr(ret,ind,1))+49)||substr(ret,ind+2); 
    SYS.Dbms_Output.Put_Line(ret); 
    end loop; 
    return ret; 
    end; 

    function replace_dd(str varchar2) return varchar2 is 
    begin 
    return convr(regexp_replace(str,'((\d)(\d))','\2#\3#')); 
    end; 
begin 
    str := '11a34'; 
    Dbms_Output.Put_Line(str); 
    Dbms_Output.Put_Line(replace_a(str)); 
    Dbms_Output.Put_Line(replace_dd(replace_a(str))); 
end; 

結果:

11a34 
115a34 
1#1#5a3#4# 
3 
1b5a3#4# 
7 
1b5a3e 
1b5a3e 
2

何が起こっているのかは、置換文字列が最初に展開され、完全に処理された後にのみ、\2のような残りの後方参照が文字列フラグメントに置き換えられます。したがって、convr('\3')が最初に処理され、この段階で'\3'はリテラルです。 ascii()は引数として受け取った文字列の最初の文字のASCIIコードを返します。だから、3つの役割を果たすことは、あなたが気づいただけでascii('\')を取得します。次に、ユーザー定義関数が評価され、連結にプラグインされます。今や置換文字列には\3が残っていません。

演習:

regexp_replace('abcdef', '(b).*(e)', '\2' || upper('\1')) 

aebfないaeBfである理由を理解/説明しよう。

入力文字列をコンポーネント文字に分割し、偶数インデックスの文字列に変換を適用し、文字列を結合して戻すことができます(すべてSQLであり、ループなどの必要はありません)。

with 
    inputs (str) as (
     select '111324' from dual union all 
     select '372' from dual 
    ), 
    singletons (str, idx, ch) as (
     select str, level, substr(str, level, 1) 
     from inputs 
     connect by level <= length(str) 
     and prior str = str 
     and prior sys_guid() is not null 
    ) 
select str, 
     listagg(case mod(idx, 2) when 1 then ch else chr(ascii(ch)+49) end, '') 
        within group (order by idx) 
     as modified_str 
from singletons 
group by str 
; 

STR MODIFIED_STR 
------ -------------- 
111324 1b1d2e 
372 3h2 
関連する問題