某个表中有一个字段是英文的字符串,单词之间用空格隔开,需要统计其中单词的个数。难点有:
            1,字符串中可能有数字,例如"I am 5 years old",数字算一个单词。因此例子中单词数为5;
            2 , 分割单词的空格可能有一到多个,例如"This is          fun"。例子中单词数为3;
Oracle中好像没有类似的函数。请教各位热心人,帮忙提供思路或参考语句。
 Thanks in advance!

解决方案 »

  1.   

    我写了个函数,由于oracle限制,只支持40000字节以内的字符串create or replace function f_getcount(a varchar2) return number is
    cnt number;
    i number;
    str varchar2(4000);
    flag number;  -- 上一个字符是否空格 1 是 0 不是
    begin
      str := a || ' ';
      cnt := 0;
      flag := 1;
      for i in 1..length(str) loop
        -- 如果遇到空格
        if substr(str,i,1) = ' ' then
          -- 判断前面是否是连续的空格,不是则认为新的单词
          if flag = 0 then
             cnt := cnt + 1;
          end if;
        end if;
        
        if substr(str,i,1) = ' ' then
          flag := 1;
        else
          flag := 0;
        end if;
      end loop;  return cnt;
    end ;
      

  2.   


    CREATE OR REPLACE FUNCTION get_words(word IN VARCHAR2 )
      RETURN NUMBER 
      IS
      num NUMBER:=0;
      BEGIN
           FOR i IN 1..Length(word) LOOP
              IF SubStr(word,i,1) = Chr(32) THEN 
                  num:=num+1;
              END IF ;
           END LOOP;
           RETURN num+1;
      END; SELECT get_words('I am 5 years old') FROM dual;
      

  3.   


    --忘记了你说不止一个空格,这个是最终版!OK!
    CREATE OR REPLACE FUNCTION get_words(word IN VARCHAR2 )
      RETURN NUMBER 
      IS
      num NUMBER:=0;
      BEGIN
           FOR i IN 1..Length(word) LOOP
              IF SubStr(word,i,1) = Chr(32) AND SubStr(word,i-1,1)!=Chr(32) THEN 
                  num:=num+1;
              END IF ;
           END LOOP;
           RETURN num+1;
      END; SELECT get_words('I am 5 years    old') FROM dual;
      

  4.   

    把空格字符用空字符代替,然后把两个长度减掉select length('I am 5 years old')-length(regexp_replace('I am 5 years old',' ',''))+1  from dual 
      

  5.   


    --补充:
    --此函数可以过滤其他标点符号(如逗号,分号。。),只要标点符号紧跟在单词后面就OK!
      CREATE OR REPLACE FUNCTION get_words(word IN VARCHAR2 )
      RETURN NUMBER
      IS
      num NUMBER:=0;
      BEGIN
           FOR i IN 1..Length(word) LOOP
              IF SubStr(word,i,1) = Chr(32) AND SubStr(word,i-1,1)!=Chr(32) THEN
                  num:=num+1;
              END IF ;
           END LOOP;
           RETURN num+1;
      END; --测试:
     SELECT get_words('My name is paddy, I am 23  years    old; I like CSDN.') words FROM dual; --结果:
              WORDS
            --------
              12
      

  6.   


    谢谢,这个也是我最初想到的思路,我写的是这个样子的:
    CREATE OR REPLACE FUNCTION get_char_count(src IN VARCHAR2, sep in varchar2)
        RETURN number
    IS
      pcount number;
    BEGIN
    pcount := ((length(src) - length(replace(src, sep)))/length(sep) + 1);
      return pcount;
    END;
    但是正如楼下所说的,对于多个空格的情况就不适用了!
      

  7.   

    select length(REGEXP_REPLACE('I am 5 years old','[ ]*[[:alnum:]]+[ ]*','@')) from  dual
      

  8.   


    显然还是欠缺
    select length(REGEXP_REPLACE('My name is paddy, I am 23 years    old, I   like  CSDN CUB.','[ ]*[[:alnum:]]+[ ]*','@')) from  dual ;
    返回16,正确应该是13
      

  9.   


    非常感谢你的回答!我认为你的答案是最完美的。我是个初选者,能否简单解释一下:
    SubStr(word,i,1) = Chr(32) AND SubStr(word,i-1,1)!=Chr(32)
    不胜感激!
      

  10.   


    ---稍微变通下哈
    ---先使用regexp_replace('I am 5 year old', '\s+', '@')把所有的连续的空格字符用@代替
    ---剩下的思路就是你最初的想法
    select length(regexp_replace('I am 5 year old', '\s+', '@')) -
           length(regexp_replace(regexp_replace('I am 5 year old', '\s+', '@'),
                                 '@',
                                 '')) + 1
      from dual
      

  11.   


    你说的可以过滤其他符号是不是要更改chr(32)变成其他字符?
      

  12.   

    --试试这个create or replace function fun_sumzf2(v_char varchar2) return number
    as
    num number:=0;
    str varchar2(100);
    j number;
    begin
    str:=trim(v_char);
    select length(str||' ')-length(replace(str||' ',' ','')) into j from dual;
    for i in 1..j loop
    if instr(str,' ',1,i)!=instr(str,' ',1,i+1)-1 then
    num:=num+1;
    end if;
    end loop;
    return num;
    end;--测试的结果SQL> select fun_sumzf2('I 2') from dual
      2  /
     
    FUN_SUMZF2('I2')
    ----------------
                   2
     
    SQL> select fun_sumzf2('I     2  b') from dual
      2  /
     
    FUN_SUMZF2('I2B')
    -----------------
                    3
     
    SQL> select fun_sumzf2('I 2 b   ') from dual
      2  /
     
    FUN_SUMZF2('I2B')
    -----------------
                    3
     
    SQL>  select fun_sumzf2('2') from dual
      2  /
     
    FUN_SUMZF2('2')
    ---------------
                  1
      

  13.   

    select length(REGEXP_REPLACE('I am 5 years old','[ ]*[[:alnum:]]+[ ]*','@')) from  dual
    这个很经典