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'
。
我一直在尝试使用 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'
。