Oracle 与 SQLLoader 中使用的正则表达式逻辑之间有区别吗?

Is there a difference between regex logic used in Oracle vs SQLLoader?

我一直在尝试使用 sqlloader 中的 regex_replace 将字符串片段解析为两个字段,ID_CLEAN_I 和 UNIT_I 使用正则表达式

^([A-Za-z]{2,4})([\s]*|[0]*| *)([1-9][0-9]{0,5})([\s]*| *)([A-Za-z])[\s]*$

像这样将数据解析为正则表达式组:

Example string: ABCD123456A
Group 1) ABCD
Group 3) 123456
Group 5) A

像这样(你可以把 :ID_I 想象成这个例子中的 ABCD123456A):

ID_CLEAN_I   EXPRESSION  "REGEXP_REPLACE(:ID_I, '^([A-Za-z]{2,4})([\s]*|[0]*| *)([1-9][0-9]{0,5})([\s]*| *)([A-Za-z])[\s]*$', '\1 \3')",
UNIT_I    EXPRESSION  "REGEXP_REPLACE(:ID_I, '^([A-Za-z]{2,4})([\s]*|[0]*| *)([1-9][0-9]{0,5})([\s]*| *)([A-Za-z])[\s]*$', '\5')"

...和 ​​SQL-Loader 永远不会得到任何匹配项,尽管如果我们在 Oracle 中使用 ABCD123456A 的测试字符串对此进行测试,例如:

SELECT REGEXP_REPLACE('ABCD123456A', '^([A-Za-z]{2,4})([\s]*|[0]*| *)([1-9][0-9]{0,5})([\s]*| *)([A-Za-z])[\s]*$', '')
FROM dual;

然后我们就可以成功得到我们想要的任何匹配组(同样主要是组 1、3 和 5)。

所以,我的问题是 SQL Loader/Oracle/Regex 专家 - Oracle Regex 和 SQL-Loader 中使用的 Regex 之间有区别吗?如果是这样,我需要如何更改我的正则表达式以使其更适合加载程序?

编辑,根据要求,这里是细节:

OPTIONS (SKIP=0,ERRORS=50,readsize=20971644,bindsize=20971520,ROWS=5000)
LOAD DATA
INFILE 'C:\Temp\text.txt'
BADFILE 'C:\Temp\text.BAD'
DISCARDFILE 'C:\Temp\text.DSC'
APPEND 
PRESERVE BLANKS
INTO MyTable
WHEN (some stuff happens)
FIELDS TERMINATED BY '|' TRAILING NULLCOLS
(
    ID_I, -- this could be 'ABCD123456A' or 'ABCD  123456  A' or 'ABCD000123456A' 
    ID_CLEAN_I   EXPRESSION  "REGEXP_REPLACE(:ID_I, '^([A-Za-z]{2,4})([\s]*|[0]*| *)([1-9][0-9]{0,5})([\s]*| *)([A-Za-z])[\s]*$', '\1 \3')", -- we want 'ABCD 123456'
    UNIT_I       EXPRESSION  "REGEXP_REPLACE(:ID_I, '^([A-Za-z]{2,4})([\s]*|[0]*| *)([1-9][0-9]{0,5})([\s]*| *)([A-Za-z])[\s]*$', '\5')" -- we want 'A'
)

/*errors - note that UNIT_I can only be a single character  A, B, C, D...

Record 1: Rejected - Error on table MyTable, column UNIT_I.
ORA-12899: value too large for column "MyTable"."UNIT_I" (actual: 11, maximum: 1)

*/

您错误地使用了方括号匹配字符列表表达式。 [\s] 将匹配文字 \ 或文字 s 字符,而不是任何空白字符。如前所述 in the documentation:

Matches any single character in the list within the brackets. In the list, all operators except these are treated as literals:

Range operator: -
POSIX character class: [: :]
POSIX collation element: [. .]
POSIX character equivalence class: [= =]

要使用括号查找空格,您需要使用字符 class、[[:space:]] 代替。但是你不需要在这里使用字符列表,如果第一个检查(即第二组)是空格后跟零;你可以使用 the \s operator,使你的模式更像:

'^([A-Za-z]{2,4})(\s*0*)([1-9][0-9]{0,5})(\s*)([A-Za-z])\s*$'

作为具有虚构值的演示:

var id_i varchar2(20);
exec :id_i := 'ABC 012345 A ';

select REGEXP_REPLACE(:ID_I, '^([A-Za-z]{2,4})(\s*0*)([1-9][0-9]{0,5})(\s*)([A-Za-z])\s*$', ' ') as id_clean_i,
       REGEXP_REPLACE(:ID_I, '^([A-Za-z]{2,4})(\s*0*)([1-9][0-9]{0,5})(\s*)([A-Za-z])\s*$', '') as unit_i
from dual;

ID_CLEAN_I           UNIT_I             
-------------------- --------------------
ABC 12345            A                   

因此您的控制文件将具有:

ID_I,
ID_CLEAN_I   EXPRESSION  "REGEXP_REPLACE(:ID_I, '^([A-Za-z]{2,4})(\s*0*)([1-9][0-9]{0,5})(\s*)([A-Za-z])\s*$', '\1 \3')",
UNIT_I       EXPRESSION  "REGEXP_REPLACE(:ID_I, '^([A-Za-z]{2,4})(\s*0*)([1-9][0-9]{0,5})(\s*)([A-Za-z])\s*$', '\5')"

您添加到问题中的三个样本值全部加载,ID_CLEAN_I 设置为 'ABCD 123456'UNIT_I 设置为 'A'