SQL 使用regexp_substr在Oracle中按空格和字符作为分隔符分割字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31654411/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-01 03:50:56  来源:igfitidea点击:

Split string by space and character as delimiter in Oracle with regexp_substr

sqlregexoraclestring-splitregexp-substr

提问by aleko_vp

I'm trying to split a string with regexp_subtr, but i can't make it work.

我正在尝试使用 regexp_subtr 拆分字符串,但无法使其工作。

So, first, i have this query

所以,首先,我有这个查询

select regexp_substr('Helloworld - test!' ,'[[:space:]]-[[:space:]]') from dual

which very nicely extracts my delimiter - blank-blank

这很好地提取了我的分隔符 -空白-空白

But then, when i try to split the string with this option, it just doesn't work.

但是,当我尝试使用此选项拆分字符串时,它不起作用。

select regexp_substr('Helloworld - test!' ,'[^[[:space:]]-[[:space:]]]+')from dual

The query returns nothing.

查询不返回任何内容。

Help will be much appreciated! Thanks

帮助将不胜感激!谢谢

回答by MT0

SQL Fiddle

SQL小提琴

Oracle 11g R2 Schema Setup:

Oracle 11g R2 架构设置

CREATE TABLE TEST( str ) AS
          SELECT 'Hello world - test-test! - test' FROM DUAL
UNION ALL SELECT 'Hello world2 - test2 - test-test2' FROM DUAL;

Query 1:

查询 1

SELECT Str,
       COLUMN_VALUE AS Occurrence,
       REGEXP_SUBSTR( str ,'(.*?)([[:space:]]-[[:space:]]|$)', 1, COLUMN_VALUE, NULL, 1 ) AS split_value
FROM   TEST,
       TABLE(
         CAST(
           MULTISET(
             SELECT LEVEL
             FROM   DUAL
             CONNECT BY LEVEL < REGEXP_COUNT( str ,'(.*?)([[:space:]]-[[:space:]]|$)' )
           )
           AS SYS.ODCINUMBERLIST
         )
       )

Results:

结果

|                               STR | OCCURRENCE |  SPLIT_VALUE |
|-----------------------------------|------------|--------------|
|   Hello world - test-test! - test |          1 |  Hello world |
|   Hello world - test-test! - test |          2 |   test-test! |
|   Hello world - test-test! - test |          3 |         test |
| Hello world2 - test2 - test-test2 |          1 | Hello world2 |
| Hello world2 - test2 - test-test2 |          2 |        test2 |
| Hello world2 - test2 - test-test2 |          3 |   test-test2 |

回答by Arun Palanisamy

If i understood correctly, this will help you. Currently you are getting output as Helloworld(with space at the end). So i assume u don't want to have space at the end. If so you can simply use the space in the delimiter also like.

如果我理解正确,这将对您有所帮助。目前,您正在获得输出Helloworld(末尾有空格)。所以我假设你不想在最后有空间。如果是这样,您也可以简单地使用分隔符中的空格。

select regexp_substr('Helloworld - test!' ,'[^ - ]+',1,1)from dual;

OUTPUT
Helloworld(No space at the end)

As u mentioned in ur comment if u want two columns output with Helloworldand test!. you can do the following.

正如你在你的评论中提到的,如果你想要两列输出Helloworldtest!。您可以执行以下操作。

select regexp_substr('Helloworld - test!' ,'[^ - ]+',1,1),
       regexp_substr('Helloworld - test!' ,'[^ - ]+',1,3) from dual;

OUTPUT
col1         col2
Helloworld   test!

回答by Sentinel

Trying to negate the match string '[[:space:]]-[[:space:]]'by putting it in a character class with a circumflex (^) to negate it will not work. Everything between a pair of square brackets is treated as a list of optional single characters except for named named character classes which expand out to a list of optional characters, however, due to the way character classes nest, it's very likely that your outer brackets are being interpreted as follows:

试图'[[:space:]]-[[:space:]]'通过将匹配字符串放入带有抑扬符 (^) 的字符类来否定匹配字符串来否定它是行不通的。一对方括号之间的所有内容都被视为可选单个字符列表,除了命名字符类扩展为可选字符列表之外,但是,由于字符类嵌套的方式,很可能您的外括号是解释如下:

  • [^[[:space:]]A single non space non left square bracket character
  • -followed by a single hyphen
  • [[:space:]]followed by a single space character
  • ]+followed by 1 or more closing square brackets.
  • [^[[:space:]]单个非空格非左方括号字符
  • -后跟一个连字符
  • [[:space:]]后跟一个空格字符
  • ]+后跟 1 个或多个右方括号。

It may be easier to convert your multi-character separator to a single character with regexp_replace, then use regex_substr to find you individual pieces:

使用 regexp_replace 将多字符分隔符转换为单个字符可能更容易,然后使用 regex_substr 找到您的各个部分:

select regexp_substr(regexp_replace('Helloworld - test!'
                                   ,'[[:space:]]-[[:space:]]'
                                   ,chr(11))
                    ,'([^'||chr(11)||']*)('||chr(11)||'|$)'
                    ,1 -- Start here
                    ,2 -- return 1st, 2nd, 3rd, etc. match
                    ,null
                    ,1 -- return 1st sub exp
                    )
  from dual;

In this code I first changed -to chr(11). That's the ASCII vertical tab (VT) character which is unlikely to appear in most text strings. Then the match expression of the regexp_substr matches all non VT characters followed by either a VT character or the end of line. Only the non VT characters are returned (the first subexpression).

在这段代码中,我首先更改-chr(11). 这是 ASCII 垂直制表符 (VT) 字符,它不太可能出现在大多数文本字符串中。然后 regexp_substr 的匹配表达式匹配所有非 VT 字符,后跟一个 VT 字符或行尾。仅返回非 VT 字符(第一个子表达式)。

回答by Gary_W

Slight improvement on MT0's answer. Dynamic count using regexp_count and proves it handles nulls where the format of [^delimiter]+ as a pattern does NOT handle NULL list elements. More info on that here: Split comma seperated values to columns

MT0 的回答略有改进。使用 regexp_count 的动态计数并证明它处理空值,其中 [^delimiter]+ 作为模式的格式不处理空列表元素。有关更多信息,请参见此处:将逗号分隔的值拆分为列

SQL> with tbl(str) as (
  2    select ' - Hello world - test-test! -  - test - ' from dual
  3  )
  4  SELECT LEVEL AS Occurrence,
  5         REGEXP_SUBSTR( str ,'(.*?)([[:space:]]-[[:space:]]|$)', 1, LEVEL, NULL, 1 ) AS split_value
  6  FROM   tbl
  7  CONNECT BY LEVEL <= regexp_count(str, '[[:space:]]-[[:space:]]')+1;

OCCURRENCE SPLIT_VALUE
---------- ----------------------------------------
         1
         2 Hello world
         3 test-test!
         4
         5 test
         6

6 rows selected.

SQL>

回答by Dan

CREATE OR REPLACE FUNCTION field(i_string            VARCHAR2
                                ,i_delimiter         VARCHAR2
                                ,i_occurance         NUMBER
                                ,i_return_number     NUMBER DEFAULT 0
                                ,i_replace_delimiter VARCHAR2) RETURN VARCHAR2     IS
  -----------------------------------------------------------------------
  -- Function Name.......: FIELD
  -- Author..............: Dan Simson
  -- Date................: 05/06/2016 
  -- Description.........: This function is similar to the one I used from 
  --                       long ago by Prime Computer.  You can easily
  --                       parse a delimited string.
  -- Example.............: 
  --  String.............: This is a cool function
  --  Delimiter..........: ' '
  --  Occurance..........: 2
  --  Return Number......: 3
  --  Replace Delimiter..: '/'
  --  Return Value.......: is/a/cool
  --------------------------------------------------------------------------    ---                                    
  v_return_string  VARCHAR2(32767);
  n_start          NUMBER := i_occurance;
  v_delimiter      VARCHAR2(1);
  n_return_number  NUMBER := i_return_number;
  n_max_delimiters NUMBER := regexp_count(i_string, i_delimiter);
BEGIN
  IF i_return_number > n_max_delimiters THEN
    n_return_number := n_max_delimiters + 1;
  END IF;
  FOR a IN 1 .. n_return_number LOOP
    v_return_string := v_return_string || v_delimiter || regexp_substr    (i_string, '[^' || i_delimiter || ']+', 1, n_start);
    n_start         := n_start + 1;
    v_delimiter     := nvl(i_replace_delimiter, i_delimiter);
  END LOOP;
  RETURN(v_return_string);
END field;


SELECT field('This is a cool function',' ',2,3,'/') FROM dual;

SELECT regexp_substr('This is a cool function', '[^ ]+', 1, 1) Word1
      ,regexp_substr('This is a cool function', '[^ ]+', 1, 2) Word2
      ,regexp_substr('This is a cool function', '[^ ]+', 1, 3) Word3
      ,regexp_substr('This is a cool function', '[^ ]+', 1, 4) Word4
      ,regexp_substr('This is a cool function', '[^ ]+', 1, 5) Word5
  FROM dual;