如何计算字符串中分隔符的出现次数,不包括引号中的分隔符

Tia*_*rge 1 regex string oracle plsql count

我有一个逗号分隔值的文件,如下所示:

1.42104E+16,220899,1,,e-page remote auto,,,"Allied Martian Banks, P.L.C.",Moon,MN,,
1.42105E+16,637039,1,,e-page remote auto,,,Bank Of Jupiter,Europa,IO,,
Run Code Online (Sandbox Code Playgroud)

我想计算一些逗号的数量,不包括引号中的那些,例如"Allied Martian Banks,PLC".

我知道:

length(i.data_record)-length(replace(i.data_record,',',''))
Run Code Online (Sandbox Code Playgroud)

将返回逗号的数量,但是这将在第一行中计算额外的逗号而不是第二行,为此我们应该将它们计为具有相同的数字.

是否有任何快速简单的方法可以忽略引号中的逗号?

我知道我可以创建一个循环并开始按位分解字符串,计算它们,每当我找到引号时忽略任何逗号,直到找到另一个引号,但是我想知道是否有更简单,更简化的方式在不诉诸循环的情况下实现这一点.

非常感谢!

col*_*sar 5

首先消除分隔的内容,然后计算:

regexp_count (
    regexp_replace (
        regexp_replace (
            i.data_record
          , '(^|,)"[^"]*"(,|$)'
          , '\1\2'
        )
      , '(^|,)"[^"]*"(,|$)'
      , '\1\2'
    )
  , ',' 
) 
Run Code Online (Sandbox Code Playgroud)

regexp_replace遗憾的是,为了正确处理连续的引号分隔字段,不需要嵌套调用:正则表达式模式消耗任何分隔逗号,因此后续匹配不会考虑这些逗号.

Oracle的regexen不支持前瞻操作符,这是处理这种情况的自然方式.

鉴于regexp _...调用的性能受到影响,您最好使用它

length(i.data_record) - length ( replace ( regexp_replace ( i.data_record, '(^|,)"[^"]*"(,|$)', '\1\2' ),',','' ) )
Run Code Online (Sandbox Code Playgroud)

警告

此解决方案不处理字段值中的dquotes,字段值通常表示为""\".

可以优雅地处理前一种情况:不要""将引号分隔字段内部解释,而是将整个字段内容视为一个或多个不包含dquotes的dquote分隔字符串的并置.虽然您在处理数据时不会遵循此路线(所有dquotes都将丢失),但您可以使用此透视图进行计数:

regexp_count (
    regexp_replace (
        regexp_replace (
            i.data_record
          , '(^|,)("[^"]*")+(,|$)'  -- changed
          , '\1\3'                  -- changed
        )
      , '(^|,)("[^"]*")+(,|$)'   -- changed
      , '\1\3'                   -- changed
    )
  , ',' 
) 
Run Code Online (Sandbox Code Playgroud)

测试用例

-- works
select regexp_count ( regexp_replace ( regexp_replace ( '1,"data,and more so","more data,and even more so"', '(^|,)"[^"]*"(,|$)', '\1\2' ), '(^|,)"[^"]*"(,|$)', '\1\2' ), ',' ) from dual;
select regexp_count ( regexp_replace ( regexp_replace ( '1,"data,and more so",2,"more data,and even more so"', '(^|,)"[^"]*"(,|$)', '\1\2' ), '(^|,)"[^"]*"(,|$)', '\1\2' ), ',' ) from dual;

select regexp_count ( regexp_replace ( regexp_replace ( '1,"""data"",and more so",2,"more data,and even more so"', '(^|,)("[^"]*")+(,|$)', '\1\3' ), '(^|,)("[^"]*")+(,|$)', '\1\3' ), ',' ) from dual;

-- fails
select regexp_count ( regexp_replace ( '1,"data,and more so","more data,and even more so"', '(^|,)"[^"]*"(,|$)', '\1\2' ), ',' ) from dual;
select regexp_count ( regexp_replace ( '1,"data,and more so",2,"more data,and even more so"', '(^|,)"[^"]*"(,|$)', '\1\2' ), ',' ) from dual;
Run Code Online (Sandbox Code Playgroud)