2017-05-28 7 views
1

TOADのSQLを使用してテーブルのDESCRIPTIONフィールドからすべての印刷不可能なASCII文字をフェッチしようとしています。SQLで印刷できないアスキー文字をASCIIで表示:ascii:または:print:は動作しません

select 
regexp_instr(a.description,'[^[:ascii:]]') as description from 
poline a where a.ponum='XXX' and a.siteid='YYY' and 
regexp_instr(a.description,'[^[:ascii:]]') > 0 

上記の問合せでエラーが発生しましたORA-127729:正規表現で無効な文字クラスです。私は試みました:印刷:代わりに:ascii:しかし、それは結果をもたらしませんでした。以下は、印刷不可能な文字を持つこのレコードの説明です。

Sherlock 16 x 6.5” Wide Wheelbarrow wheel .M100P.10R – Effluent care bacteria and enzyme formulation 
+0

ありがとうございますmax092012行ごとに印刷できない文字がすべて出現するのを探しているのか、最初の出現しか見たくないのでしょうか? – alexgibbs

答えて

1

:ascii:(アスキーはない文字を含んでいます)の有効な文字クラスではありません、それがあったとしても、あなたがここに取得しようとしているものではありません。有効なクラスはhereです。

実際に元のクエリで:ascii::print:に置き換えた場合、実際には印刷可能でない文字の各POLINE.DESCRIPTIONの最初の位置が返されます。 (それはあなたのために何も返さない場合は、あなたのDESCRIPTIONデータが実際にすべて印刷可能であるので、それはかもしれません。)

しかし、あなたは、POLINEにいくつかの変更を各DESCRIPTION内のすべての非印字文字を識別したい述べたように必要となるだろう。すべてのマッチを開始場所として取得する例を紹介します。

この例では、各DESCRIPTIONは個々の構成文字に分解され、各文字は印刷可能かどうかがチェックされます。 DESCRIPTION文字列内の位置と、印刷不能文字のASCII numberが返されます。

この例では、各行の一意の識別子がPOLINE(ここではPOLINE_ID)であることを前提としています。

まず、テストテーブルを作成します。

CREATE TABLE POLINE(
    POLINE_ID NUMBER PRIMARY KEY, 
    PONUM VARCHAR2(32), 
    SITEID VARCHAR2(32), 
    DESCRIPTION VARCHAR2(256) 
); 

そして、いくつかのデータをロードします。あなたが提供したSherlock文字列の例では、いくつかの非印字文字を挿入しました。#23#17です。最初の64個のASCII文字(最初の31文字は:print:に含まれていません)だけで構成された文字列の例と、PONUMSITEIDという述語を使用するフィラーも含まれています。

INSERT INTO POLINE VALUES (1,'XXX','YYY','Sherlock'||CHR(23)||' 16 x 6.5” Wide Wheelbarrow wheel .M100P.10R –'||CHR(17)||' Effluent care bacteria and enzyme formulation'); 

DECLARE 
    V_STRING VARCHAR2(64) := CHR(1); 
BEGIN 
    FOR POINTER IN 2..64 LOOP 
    V_STRING := V_STRING||CHR(POINTER); 
    END LOOP; 
    INSERT INTO POLINE VALUES (2, 'XXX','YYY',V_STRING); 
    INSERT INTO POLINE VALUES (3, 'AAA','BBB',V_STRING); 
END; 
/

INSERT INTO POLINE VALUES(4,'XXX','YYY','VOLTRON'); 

ここでは合計4行です。それらのうちの3つには、複数の印刷不能文字が含まれていますが、それらのうち2つだけがすべての制限に一致する必要があります。

次に、クエリを実行します。以下の2つの例のクエリがあります。最初のクエリではを:print:に置き換えて、最初の例のクエリと同じようにREGEXP_INSTRを使用します。しかし、代わりに、2番目のバリエーションも含まれています。これは、各文字が最初の31文字のascii文字に含まれているかどうかをチェックするだけです。

DESCRIPTIONのすべての文字をインデックスに付け、印刷可能かどうかを確認し、各候補内の各印刷不可能文字のアスキー番号と場所を収集します。DESCRIPTIONここの表の例は、長さが256文字のDESCRIPTIONです。したがって、これは、デカルト結合の最大インデックスとして使用されます。

注意してください、これらは効率的ではない、とEVERY試合を取得するために設計されています。あなたが最初のマッチafterallだけを必要とするなら、元のクエリは:print:に置き換えられます。また、これはPL/SOLにドロップするか、または再帰的に(PL/SQLがユースケースで許可されている場合、または11gR2 +などである場合)、チューニングすることもできます。また、REGEXP_LIKEのようなここの述部は、最終結果に影響を与えず、予備的な濾過を可能にするだけの役割を果たす。あなたのデータセットに応じて、これらはあなたのために不必要(または悪い)になる可能性があります。 ASCII番号を使って正規表現と:print:

SELECT 
    POLINE_ID, 
    STRING_INDEX                  AS NON_PRINTABLE_LOCATION, 
    ASCII(REGEXP_SUBSTR(SUBSTR(DESCRIPTION, STRING_INDEX, 1), '[[:cntrl:]]', 1, 1)) AS NON_PRINTABLE_ASCII_NUMBER 
FROM POLINE 
    CROSS JOIN (SELECT LEVEL AS STRING_INDEX 
       FROM DUAL 
       CONNECT BY LEVEL < 257) CANDIDATE_LOCATION 
WHERE PONUM = 'XXX' 
     AND SITEID = 'YYY' 
     AND REGEXP_LIKE(DESCRIPTION, '[[:cntrl:]]') 
     AND REGEXP_INSTR(SUBSTR(DESCRIPTION, STRING_INDEX, 1), '[[:cntrl:]]', 1, 1, 0) > 0 
     AND STRING_INDEX <= LENGTH(DESCRIPTION) 
ORDER BY 1 ASC, 2 ASC; 

第二の例を使用して

まずたとえば、:

SELECT 
    POLINE_ID, 
    STRING_INDEX        AS NON_PRINTABLE_LOCATION, 
    ASCII(SUBSTR(DESCRIPTION, STRING_INDEX, 1)) AS NON_PRINTABLE_ASCII_NUMBER 
FROM POLINE 
    CROSS JOIN (SELECT LEVEL AS STRING_INDEX 
       FROM DUAL 
       CONNECT BY LEVEL < 257) CANDIDATE_LOCATION 
WHERE PONUM = 'XXX' 
     AND SITEID = 'YYY' 
     AND REGEXP_LIKE(DESCRIPTION, '[[:cntrl:]]') 
     AND ASCII(SUBSTR(DESCRIPTION, STRING_INDEX, 1)) BETWEEN 1 AND 31 
     AND STRING_INDEX <= LENGTH(DESCRIPTION) 
ORDER BY 1 ASC, 2 ASC; 

我々のテストデータでは、これらのクエリは同等の出力を生成します。 SherlockDESCRIPTIONには2ヒット(chrs 17と23)があり、最初の64-ascii DESCRIPTIONには31ヒットとなるはずです。

結果:コメントに応えて

POLINE_ID NON_PRINTABLE_LOCATION NON_PRINTABLE_ASCII_NUMBER 
1   9      23       
1   56      17       
2   1      1       
2   2      2       
2   3      3       
2   4      4       
2   5      5       
2   6      6       
2   7      7       
2   8      8       
2   9      9       
2   10      10       
2   11      11       
2   12      12       
2   13      13       
2   14      14       
2   15      15       
2   16      16       
2   17      17       
2   18      18       
2   19      19       
2   20      20       
2   21      21       
2   22      22       
2   23      23       
2   24      24       
2   25      25       
2   26      26       
2   27      27       
2   28      28       
2   29      29       
2   30      30       
2   31      31      

33 rows selected. 

EDITは、ここで我々は[[:cntrl:]][^[:cntrl:]]からregexp_instrと期待できることにいくつかの工夫です。

[[:cntrl:]]は最初の31文字のASCII文字のいずれかに一致し、[^[:cntrl:]]は論理否定が[[:cntrl:]]であるため、最初の31文字のASCII文字以外は一致します。
これらを比較するには、最も単純な場合は1文字だけ開始することができます(ascii #31)。 1つの文字しかないので、結果は一致するものと見逃すもののどちらでもかまいません。今、私たちは2つ(またはそれ以上を含む場合

SELECT REGEXP_INSTR(CHR(31),'[^[:cntrl:]]',1,1,0) AS MATCH_INDEX FROM DUAL; 

MATCH_INDEX 
0 

:[:CNTRL:] [^]否定するとミスのため

SELECT REGEXP_INSTR(CHR(31),'[[:cntrl:]]',1,1,0) AS MATCH_INDEX FROM DUAL; 

MATCH_INDEX 
1 

しかし、0:一つは、次の試合のために1を返すことを期待します)文字が印刷可能と印刷不能の組み合わせである場合、より多くの可能性があります。 [[:cntrl:]][^[:cntrl:]]の両方が一致しますが、異なるものにしか一致しません。 ascii #31からascii #64#31に移動すると、[[:cntrl:]]が一致することが期待されます(2番目の位置に印刷できない文字があるため)が、2番目の位置に印刷不能なので2を返します。

SELECT REGEXP_INSTR(CHR(64)||CHR(31),'[[:cntrl:]]',1,1,0) AS MATCH_INDEX FROM DUAL; 

MATCH_INDEX 
2 

そして今[^[:cntrl:]]は、(第1の位置)と一致する機会を持っている:

SELECT REGEXP_INSTR(CHR(64)||CHR(31),'[^[:cntrl:]]',1,1,0) AS MATCH_INDEX FROM DUAL; 

MATCH_INDEX 
1 

印刷可能と制御文字が混在している場合は、[[:cntrl:]][^[:cntrl:]]の両方が一致することができ、彼らは異なる指数で一致します。

+0

詳細な説明をいただきありがとうございます。私の要件は、記述フィールドの任意の位置に印刷できないアスキー文字を選択することです。私はいくつかのテストに遭遇しましたが、[^ [:cntrl:]]は動作しますが、[[:cntrl:]] +も動作しますが、どちらも異なる結果をもたらします。あなたは同じものの違いを詳しく教えてもらえますか?再度、感謝します!! – max092012

+0

ありがとう@ max092012数時間後(タイムゾーンの遅い)、[^ [:cntrl:]] vs [[:cntrl:]]についてフォローアップします。これらによって生成される効果的なマッチャーは実際には異なるので、合理的であると思われます。あなたの場合、私は[:cntrl:]があなたの目標だと信じています。私はこれらの文字クラスについていくつか追加した後にフォローアップします。ありがとう – alexgibbs

+0

ありがとう@ max092012 'regexp_instr'の' [[:cntrl:]] 'vs' [^ [:cntrl:]] 'を使って、さまざまな文字の組み合わせに対して、これはクエリを明確にするのに役立ちますか?ありがとう – alexgibbs

関連する問題