2017-05-28 143 views
1

我想從TOAD中使用SQL的表中的描述字段獲取所有不可打印的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:不是有效的字符類,即使它是,它並不顯得你正在嘗試到這裏(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行。其中三個包含(多個)不可打印字符,但其中只有兩個應匹配所有限制。

然後運行查詢。下面有兩個示例查詢 - 第一個使用REGEXP_INSTR,與您在初始示例查詢中一樣(將:cntrl:替換爲:print:)。但是,對於另一種選擇,還包括第二個變體,它只檢查每個字符是否在前31個ASCII字符中。

這兩個示例查詢都將索引每個DESCRIPTION的每個字符,並檢查它是否可打印,並收集每個候選DESCRIPTION中每個不可打印字符的ASCII碼和位置。這裏的示例表具有長度爲256個字符的DESCRIPTION s,所以這被用作笛卡爾連接中的最大索引。

請注意,這些都是效率不高,並設計讓EVERY比賽。如果您最終只需要第一場比賽,您的原始查詢替換爲:print:將表現更好。此外,還可以通過放入PL/SOL或者遞歸(如果PL/SQL在您的用例中允許,或者您是11gR2 +等)來調整。此處的一些謂詞如REGEXP_LIKE不會影響最終結果,僅用於初步過濾。根據您的數據集,這些對您來說可能是多餘的(或更糟糕的)。

第一個例子,使用正則表達式和: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; 

第二個例子,用ASCII碼:

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; 

在我們的測試數據,這些查詢會產生相同的輸出。我們應該預計這將有兩個命中(第17和23號)在SherlockDESCRIPTION和31命中的前64-ascii DESCRIPTION

結果:

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. 

編輯在迴應評論,這裏是什麼,我們可以期待[[:cntrl:]][^[:cntrl:]]regexp_instr一些闡述。

[[:cntrl:]]將匹配任何第一31個ASCII字符,而[^[:cntrl:]][[:cntrl:]]邏輯非,所以除了第31個ASCII字符,它將匹配任何東西。
要比較這些,我們可以從最簡單的情況開始,只有一個字符ascii #31。由於只有一個字符,結果只能是匹配或未命中。一會期待下返回1的比賽:

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

MATCH_INDEX 
1 

但0的小姐否定[^ [:CNTRL:]:

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

MATCH_INDEX 
0 

現在,如果我們有兩個(或更多)是可打印和不可打印的混合字符,因此會有更多可能的結果。 [[:cntrl:]][^[:cntrl:]]可以匹配,但他們只能匹配不同的東西。如果我們只從ascii #31移動到ascii #64#31,我們仍然期望[[:cntrl:]]匹配(因爲在第二個位置有一個不可打印的字符),但現在應該返回2,因爲不可打印位於第二個位置。

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

MATCH_INDEX 
2 

現在[^[:cntrl:]]有機會匹配(在第一位置):

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

MATCH_INDEX 
1 

當有可打印和控制字符的組合,既[[:cntrl:]][^[:cntrl:]]可以匹配,但他們會匹配不同的指數。

+0

非常感謝您的詳細解釋。我的要求是在描述字段中的任何位置選擇不可打印的ascii字符。我遇到了一些測試,[^ [:cntrl:]]工作,但[[:cntrl:]] +也可以工作,但它們都帶來不同的結果。你能否詳細說明相同的區別?再次感謝!! – max092012

+0

謝謝@ max092012這將是幾個小時(在我的時區後期),但我確定我會跟進[^ [:cntrl:]]和[[:cntrl:]]。由這些產生的有效匹配確實是不同的,所以他們產生不同的結果似乎是合理的。在你的情況下,我相信[:cntrl:]是你的目標。添加一些關於這些角色類的內容後,我會跟進。謝謝 – alexgibbs

+0

謝謝@ max092012我在帖子的底部添加了一個關於'regexp_instr'與'[[:cntrl:]]'vs'[^ [:cntrl:]]'對不同字符組合的行爲的部分。這有助於澄清查詢嗎?謝謝 – alexgibbs