: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:
中),以及一些填充符通過PONUM
和SITEID
謂詞。
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號)在Sherlock
DESCRIPTION
和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:]]
可以匹配,但他們會匹配不同的指數。
謝謝max092012。你是否希望每行都出現一個不可打印的字符,或者只是第一次出現? – alexgibbs