web-dev-qa-db-ja.com

Oracle Varchar2からの非ASCII文字の検索と削除

現在、Oracleデータベースの1つをUTF8に移行していますが、4000バイトのvarchar制限に近いレコードがいくつか見つかりました。これらのレコードを移行しようとすると、マルチバイトUF8文字になる文字が含まれているため失敗します。 PL/SQL内で実行したいのは、これらの文字を見つけて内容を確認し、それらを変更するか削除することです。

私がやりたい:

SELECT REGEXP_REPLACE(COLUMN,'[^[:ascii:]],'')

しかし、Oracleは[:ascii:]文字クラスを実装していません。

私がやりたいことをする簡単な方法はありますか?

24
Paul Gilfedder

シングルバイトASCII互換エンコーディング(Latin-1など)では、ASCII文字は0〜127の範囲の単なるバイトです。したがって、[\x80-\xFF]非ASCII文字を検出します。

7
Max Shawabkeh

ASCIISTR関数を使用してUnicodeを\nnnnの形式のリテラルに変換する場合、REGEXP_REPLACEを使用してこれらのリテラルを削除できます。

UPDATE table SET field = REGEXP_REPLACE(ASCIISTR(field), '\\[[:xdigit:]]{4}', '')

...ここで、フィールドとテーブルはそれぞれフィールド名とテーブル名です。

23
Robb Smith

これでうまくいくと思います:

SELECT REGEXP_REPLACE(COLUMN, '[^[:print:]]', '')
21
Yuri Tkachenko

実動コードには推奨しませんが、それは理にかなっており、動作するようです:

SELECT REGEXP_REPLACE(COLUMN,'[^' || CHR(1) || '-' || CHR(127) || '],'')
9
Francisco Hayoz

選択は次のサンプルのようになります。

select nvalue from table
where length(asciistr(nvalue))!=length(nvalue)  
order by nvalue;
4
Jeff Dwight

以下も機能します。

select dump(a,1016), a from (
SELECT REGEXP_REPLACE (
          CONVERT (
             '3735844533120%$03  ',
             'US7ASCII',
             'WE8ISO8859P1'),
          '[^!@/\.,;:<>#$%&()_=[:alnum:][:blank:]]') a
  FROM DUAL);
3
Sajid

おそらく正規表現を使用するより直接的な方法があります。運が良ければ、他の誰かがそれを提供します。しかし、ここでは、マニュアルにアクセスすることなく行うことができます。

入力文字列を受け取り、varchar2を返すPLSQL関数を作成します。

PLSQL関数で、入力のasciistr()を実行します。 PLSQLは、4000文字を超える文字列を返す可能性があり、PLSQLでvarchar2に32Kを使用できるためです。

この関数は、非ASCII文字を\ xxxx表記に変換します。したがって、正規表現を使用してそれらを検索および削除できます。その後、結果を返します。

3
Jim Hudson

以下を試してください:

-- To detect
select 1 from dual
where regexp_like(trim('xx test text æ¸¬è© ¦ “xmx” number²'),'['||chr(128)||'-'||chr(255)||']','in')

-- To strip out
select regexp_replace(trim('xx test text æ¸¬è© ¦ “xmxmx” number²'),'['||chr(128)||'-'||chr(255)||']','',1,0,'in')
from dual
2
Kok-Yan Lo

同様の問題があり、それについてブログに書いていました here 。私は英数字の正規表現から始め、次に好きないくつかの基本的な句読文字を追加しました。

select dump(a,1016), a, b
from
 (select regexp_replace(COLUMN,'[[:alnum:]/''%()> -.:=;[]','') a,
         COLUMN b
  from TABLE)
where a is not null
order by a;

1016バリアントのダンプを使用して、utl_raw.cast_to_varchar2でユーザーが使用できる16進文字を置き換えました。

2
Gary Myers

私はここで答えを見つけました:

http://www.squaredba.com/remove-non-ascii-characters-from-a-column-255.html

CREATE OR REPLACE FUNCTION O1DW.RECTIFY_NON_ASCII(INPUT_STR IN VARCHAR2)
RETURN VARCHAR2
IS
str VARCHAR2(2000);
act number :=0;
cnt number :=0;
askey number :=0;
OUTPUT_STR VARCHAR2(2000);
begin
str:=’^'||TO_CHAR(INPUT_STR)||’^';
cnt:=length(str);
for i in 1 .. cnt loop
askey :=0;
select ascii(substr(str,i,1)) into askey
from dual;
if askey < 32 or askey >=127 then
str :=’^'||REPLACE(str, CHR(askey),”);
end if;
end loop;
OUTPUT_STR := trim(ltrim(rtrim(trim(str),’^'),’^'));
RETURN (OUTPUT_STR);
end;
/

次に、これを実行してデータを更新します

update o1dw.rate_ipselect_p_20110505
set NCANI = RECTIFY_NON_ASCII(NCANI);
2
Matt McGurie

次のようなものを試して、非ASCII文字を含む列を検索できます。

select * from your_table where your_col <> asciistr(your_col);
1

おかげで、これは私の目的のために働いた。ところで、上記の例では、単一引用符が欠落しています。

REGEXP_REPLACE(COLUMN、 '[^' || CHR(32)|| '-' || CHR(127)|| ']'、 ''))

ワードラップ機能で使用しました。場合によっては、受信テキストに混乱を招く埋め込みNewLine/NL/CHR(10)/ 0Aがありました。

0
allen

使用するときはいつでも

regexp_like(column, '[A-Z]')

Oracleの正規表現エンジンは、Latin-1の範囲の特定の文字にも一致します。これは、ASCIIÄ-> A、Ö-> O、Ü->のような文字に類似するすべての文字に適用されます。 Uなど。したがって、[AZ]は、Perlなどの他の環境から知っているものではありません。

正規表現をいじる代わりに、文字セットをアップグレードする前にNVARCHAR2データ型を変更してください。

別のアプローチ:データベースにヨーロッパ文字(つまりLatin-1)文字のみが含まれている場合、フィールドのコンテンツの一部を切り取る代わりに、SOUNDEX関数を試すことができます。または、Latin-1の範囲の文字を似たようなASCII文字、たとえば

  • å=> a
  • ä=> a
  • ö=> o

もちろん、UTF-8に変換されたときに4000バイトを超えるテキストブロックに対してのみ。

0
elwood

Francisco Hayozの回答が最高です。 sqlでできる場合は、pl/sql関数を使用しないでください。

Oracle 11.2.03の簡単なテストを次に示します

select s
     , regexp_replace(s,'[^'||chr(1)||'-'||chr(127)||']','') "rep ^1-127"
     , dump(regexp_replace(s,'['||chr(127)||'-'||chr(225)||']','')) "rep 127-255"
from (
select listagg(c, '') within group (order by c) s
  from (select 127+level l,chr(127+level) c from dual connect by level < 129))

「rep 127-255」は

Typ = 1 Len = 30:226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255

つまり、何らかの理由でこのバージョンのOracleはchar(226)以上を置き換えません。 '[' || chr(127)|| '-' || chr(225)|| ']'を使用すると、望ましい結果が得られます。他の文字を置き換える必要がある場合は、上記の正規表現に追加するか、置換が異なる場合はネストされたreplace | regexp_replaceを使用してください。

0
Alex S