Oracle与SQLLoader中使用的正则表达式逻辑之间是否存在差异?

时间:2016-05-11 14:08:00

标签: sql regex oracle sql-loader

我一直在尝试在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]*$', '\5')
FROM dual;

然后我们可以成功获得我们想要的任何匹配组(主要是第1,3和5组)。

所以,我的问题是针对你的SQL Loader / Oracle / Regex大师 - SQL Reader中使用的Oracle Regex和Regex之间有区别吗?如果是这样,我将如何更改我的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)

*/

1 个答案:

答案 0 :(得分:0)

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

  

匹配括号内列表中的任何单个字符。在列表中,除这些之外的所有运算符都被视为文字:

     

范围运算符: -
  POSIX字符类:[::]   POSIX校对元素:[。 ]
  POSIX字符等价类:[= =]

要使用括号查找空格,您需要使用字符类[[: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*$', '\1 \3') 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*$', '\5') 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'