通过 Oracle 的 REGEXP_SUBSTR 排除正则表达式中的一系列字符
Exclude a series of characters in regex via Oracle's REGEXP_SUBSTR
我正在尝试使用 Oracle 的 REGEXP_SUBSTR 到 select 字符串中的字段。
示例:
this,,,is,,,an,,,example
解决方案:
DECLARE
field1 VARCHAR2(4000);
field2 VARCHAR2(4000);
field3 VARCHAR2(4000);
field4 VARCHAR2(4000);
separator VARCHAR2(300) := ',,,';
lineToParse VARCHAR2(4000) := 'this,,,is,,,an,,,example';
BEGIN
SELECT REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 1) AS part_1, REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 2) AS part_2, REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 3) AS part_3, REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 4) AS part_4
INTO field1, field2, field3, field4
FROM DUAL;
DBMS_OUTPUT.PUT_LINE('Field 1: ' || field1);
DBMS_OUTPUT.PUT_LINE('Field 2: ' || field2);
DBMS_OUTPUT.PUT_LINE('Field 3: ' || field3);
DBMS_OUTPUT.PUT_LINE('Field 4: ' || field4);
END;
这对上面的行非常有效,生成:
Field 1: this
Field 2: is
Field 3: an
Field 4: example
但是对于下面的行,它不会
this,,,is, a perfectly fine,,,new,,, line
这是因为第二个捕获组应该是:"is, a perfectly fine"
但最终成为 "is".
输出为:
Field 1: this
Field 2: is
Field 3: a perfectly fine
Field 4: new
原因是我使用的正则表达式:
[^,,,]+
正在捕获 ^ 之后的任何字符而不是序列。
如何调整我的正则表达式以便捕获整个序列?
这需要与 Oracle 11g 兼容。
我不认为你可以在这里做一个简单的正则表达式。首先,您使用的字符 class [^,,,]
与 [^,]
没有任何不同 - 方括号中的重复字符不会导致字符串中的重复字符成为匹配。其次,我认为负匹配不会起作用,因为 Oracle 正则表达式不支持环视。
您可以尝试如下操作:
SELECT REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 1) AS part_1
, REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 2) AS part_2
, REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 3) AS part_3
, REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 4) AS part_4
INTO field1, field2, field3, field4
FROM DUAL;
这将以非贪婪的方式将所有内容获取到分隔符或行尾。现在唯一的问题是返回的值可能包含分隔符;有一些方法可以避免这种情况,其中最直接的方法是使用 REPLACE()
,但是对于 Oracle 11,您还可以使用带有 REGEXP_SUBSTR()
:
的子表达式
SELECT REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 1, 'c', 1) AS part_1
, REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 2, 'c', 1) AS part_2
, REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 3, 'c', 1) AS part_3
, REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 4, 'c', 1) AS part_4
INTO field1, field2, field3, field4
FROM DUAL;
但是,如果 lineToParse
以分隔符开头,那么您仍然需要以某种方式处理它。将 REGEXP_SUBSTR()
的第一个实例更改为此似乎有效:
REGEXP_SUBSTR(lineToParse, '^(' || separator || ')?(.+?)($|' || separator || ')', 1, 1, 'c', 2) AS part_1
希望对您有所帮助。
只需将您的正则表达式调用更改为:
REGEXP_SUBSTR(lineToParse, '(.*?)(' || separator || '|$)', 1, 1, NULL, 1) AS part_1,
这定义了一组字符,后跟一组由您的分隔符或行尾组成的字符。它匹配该组的第 1 次出现(第 4 个参数)和 returns 第 1 组(第 6 个参数)。
奖金!
更好的是,构建一个函数,您可以将其放入封装此功能并调用的实用程序包中以供重用。这样,不熟悉正则表达式的人就可以使用它,如果需要更改,您只需更改一个地方的正则表达式代码:
FUNCTION GET_LIST_ELEMENT(string_in VARCHAR2, element_in NUMBER, delimiter_in VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS
BEGIN
if string_in is null then
return NULL;
else
RETURN REGEXP_SUBSTR(string_in, '(.*?)(\' || delimiter_in || '|$)', 1, element_in, NULL, 1);
end if;
END GET_LIST_ELEMENT;
那么您的代码将如下所示:
util.get_list_element(lineToParse, 1, separator) AS part_1,
util.get_list_element(lineToParse, 2, separator) AS part_2,
util.get_list_element(lineToParse, 3, separator) AS part_3,
util.get_list_element(lineToParse, 4, separator) AS part_4
我正在尝试使用 Oracle 的 REGEXP_SUBSTR 到 select 字符串中的字段。
示例:
this,,,is,,,an,,,example
解决方案:
DECLARE
field1 VARCHAR2(4000);
field2 VARCHAR2(4000);
field3 VARCHAR2(4000);
field4 VARCHAR2(4000);
separator VARCHAR2(300) := ',,,';
lineToParse VARCHAR2(4000) := 'this,,,is,,,an,,,example';
BEGIN
SELECT REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 1) AS part_1, REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 2) AS part_2, REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 3) AS part_3, REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 4) AS part_4
INTO field1, field2, field3, field4
FROM DUAL;
DBMS_OUTPUT.PUT_LINE('Field 1: ' || field1);
DBMS_OUTPUT.PUT_LINE('Field 2: ' || field2);
DBMS_OUTPUT.PUT_LINE('Field 3: ' || field3);
DBMS_OUTPUT.PUT_LINE('Field 4: ' || field4);
END;
这对上面的行非常有效,生成:
Field 1: this
Field 2: is
Field 3: an
Field 4: example
但是对于下面的行,它不会
this,,,is, a perfectly fine,,,new,,, line
这是因为第二个捕获组应该是:"is, a perfectly fine" 但最终成为 "is".
输出为:
Field 1: this
Field 2: is
Field 3: a perfectly fine
Field 4: new
原因是我使用的正则表达式:
[^,,,]+
正在捕获 ^ 之后的任何字符而不是序列。
如何调整我的正则表达式以便捕获整个序列?
这需要与 Oracle 11g 兼容。
我不认为你可以在这里做一个简单的正则表达式。首先,您使用的字符 class [^,,,]
与 [^,]
没有任何不同 - 方括号中的重复字符不会导致字符串中的重复字符成为匹配。其次,我认为负匹配不会起作用,因为 Oracle 正则表达式不支持环视。
您可以尝试如下操作:
SELECT REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 1) AS part_1
, REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 2) AS part_2
, REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 3) AS part_3
, REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 4) AS part_4
INTO field1, field2, field3, field4
FROM DUAL;
这将以非贪婪的方式将所有内容获取到分隔符或行尾。现在唯一的问题是返回的值可能包含分隔符;有一些方法可以避免这种情况,其中最直接的方法是使用 REPLACE()
,但是对于 Oracle 11,您还可以使用带有 REGEXP_SUBSTR()
:
SELECT REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 1, 'c', 1) AS part_1
, REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 2, 'c', 1) AS part_2
, REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 3, 'c', 1) AS part_3
, REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 4, 'c', 1) AS part_4
INTO field1, field2, field3, field4
FROM DUAL;
但是,如果 lineToParse
以分隔符开头,那么您仍然需要以某种方式处理它。将 REGEXP_SUBSTR()
的第一个实例更改为此似乎有效:
REGEXP_SUBSTR(lineToParse, '^(' || separator || ')?(.+?)($|' || separator || ')', 1, 1, 'c', 2) AS part_1
希望对您有所帮助。
只需将您的正则表达式调用更改为:
REGEXP_SUBSTR(lineToParse, '(.*?)(' || separator || '|$)', 1, 1, NULL, 1) AS part_1,
这定义了一组字符,后跟一组由您的分隔符或行尾组成的字符。它匹配该组的第 1 次出现(第 4 个参数)和 returns 第 1 组(第 6 个参数)。
奖金!
更好的是,构建一个函数,您可以将其放入封装此功能并调用的实用程序包中以供重用。这样,不熟悉正则表达式的人就可以使用它,如果需要更改,您只需更改一个地方的正则表达式代码:
FUNCTION GET_LIST_ELEMENT(string_in VARCHAR2, element_in NUMBER, delimiter_in VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS
BEGIN
if string_in is null then
return NULL;
else
RETURN REGEXP_SUBSTR(string_in, '(.*?)(\' || delimiter_in || '|$)', 1, element_in, NULL, 1);
end if;
END GET_LIST_ELEMENT;
那么您的代码将如下所示:
util.get_list_element(lineToParse, 1, separator) AS part_1,
util.get_list_element(lineToParse, 2, separator) AS part_2,
util.get_list_element(lineToParse, 3, separator) AS part_3,
util.get_list_element(lineToParse, 4, separator) AS part_4