博客 / 詳情

返回

[20260228]如何實現字符串拆分輸出數字序列.txt

[20260228]如何實現字符串拆分輸出數字序列.txt

--//工作需要,需要實現輸入字符串拆分輸出數字序列。比如:
--//輸入 1-3,5,7-10,44
--//輸出 1,2,3,5,7,8,9,10,44

--//想了半天感覺不好寫,上kimi查詢,自己改了一改,修改如下:

$ cat numlist2.sh
#! /bin/bash
echo "$1" | awk '{n=split($0,a,","); for(i=1;i<=n;i++){if(a[i]~/-/){split(a[i],b,"-"); for(j=b[1];j<=b[2];j++)printf j","}else printf a[i]","}}' | sed 's/,$/\n/'

--//該版本比較複雜。
--//其中給出一個版本測試存在問題,seq ${r/-/ }後面的參數被當作一個參數,執行報錯:
--//bash
numlist() { local IFS=,; for r in $1; do [[ $r =~ - ]] && seq ${r/-/ } | tr '\n' , || echo -n "$r,"; done | sed 's/,$//'; }
numlist "2-5,7,10"

--//不過很好更正,改寫如下:

$ cat ./numlist.sh
#! /bin/bash
IFS=,
for r in $1
do
     [[ $r =~ - ]] &&  eval seq ${r/-/ } || echo  "$r"
done  | paste -sd,

--//AI給出的解決方案,感覺沒我改寫的簡單明瞭!

$ ./numlist.sh "1- 3, 5, 7-10,44"
1,2,3, 5,7,8,9,10,44
--//輸入存在空格單個數字會原樣輸出,這個問題不是很大。在循環體內修改IFS定義,修改echo $r就可以了:
 $ cat numlist.sh
#! /bin/bash
IFS=,
for r in ${1}
do
     IFS=' \t\n'
     [[ $r =~ - ]] &&  eval seq ${r/-/ } || echo $r
done  | paste -sd,

$ ~/sqllaji/bin/numlist.sh " 1 - 3, 5 ,      7 -10,44"
1,2,3,5,7,8,9,10,44

--//寫成一行的腳本如下:
$ cat numlist.sh
#! /bin/bash
IFS=, ; for r in $1  ; do IFS=' \t\n';[[ $r =~ - ]] &&  eval seq ${r/-/ } || echo  $r; done  | paste -sd,

--//缺點無法刪除重複值,不過這個很容易修改,加入sort -n,uniq過濾管道就可以了。最終修改如下:
$ cat numlist.sh
#! /bin/bash
IFS=,
for r in ${1}
do
     IFS=' \t\n'
     [[ $r =~ - ]] &&  eval seq ${r/-/ } || echo $r
done  | sort -n | uniq |paste -sd,

--//寫sql語句呢?
--//sql
WITH input_data AS (
    -- 輸入字符串
    SELECT '&1' AS input_str FROM DUAL
),
split_parts AS (
    -- 步驟1:按逗號拆分
    SELECT
        REGEXP_SUBSTR(input_str, '[^,]+', 1, LEVEL) AS part
    FROM input_data
    CONNECT BY REGEXP_SUBSTR(input_str, '[^,]+', 1, LEVEL) IS NOT NULL
),
expanded AS (
    -- 步驟2:處理每個部分(範圍或單個數字)
    SELECT
        CASE
            -- 如果是範圍格式(如 2-5)
            WHEN INSTR(part, '-') > 0 THEN
                TO_NUMBER(REGEXP_SUBSTR(part, '^[0-9]+'))
            -- 如果是單個數字
            ELSE TO_NUMBER(part)
        END AS start_num,
        CASE
            WHEN INSTR(part, '-') > 0 THEN
                TO_NUMBER(REGEXP_SUBSTR(part, '[0-9]+$'))
            ELSE TO_NUMBER(part)
        END AS end_num
    FROM split_parts
),
-- 步驟3:使用遞歸生成序列
numbers(n, end_n) AS (
    SELECT start_num, end_num FROM expanded
    UNION ALL
    SELECT n + 1, end_n
    FROM numbers
    WHERE n < end_n
)
-- 最終結果
SELECT
-- distinct n AS result_number
LISTAGG (distinct n, ',') WITHIN GROUP (ORDER BY n) num_lists
    FROM numbers
ORDER BY n;

--// Oracle 10g 兼容版本(非遞歸)
WITH input_data AS (SELECT '2-5,7,10' AS input_str FROM DUAL),
split_parts AS (
    SELECT REGEXP_SUBSTR(input_str, '[^,]+', 1, LEVEL) AS part
    FROM input_data
    CONNECT BY REGEXP_SUBSTR(input_str, '[^,]+', 1, LEVEL) IS NOT NULL
),
expanded AS (
    SELECT
        TO_NUMBER(REGEXP_SUBSTR(part, '^[0-9]+')) AS start_num,
        CASE
            WHEN INSTR(part, '-') > 0
            THEN TO_NUMBER(REGEXP_SUBSTR(part, '[0-9]+$'))
            ELSE TO_NUMBER(REGEXP_SUBSTR(part, '^[0-9]+'))
        END AS end_num
    FROM split_parts
)
SELECT start_num + LEVEL - 1 AS result_number
FROM expanded
CONNECT BY LEVEL <= end_num - start_num + 1
AND PRIOR start_num = start_num  -- 防止笛卡爾積
AND PRIOR SYS_GUID() IS NOT NULL
ORDER BY result_number;

--//第2個寫法使用CONNECT BY,連接的條件非常特別PRIOR start_num = start_num,後面好跟着PRIOR SYS_GUID() IS NOT NULL。
--//而且這個版本字符串中間不能存在空格並且沒有去除重複值,修改如下:

$ cat ff1.sql
WITH input_data AS (SELECT '&&1' AS input_str FROM DUAL),
split_parts AS (
    SELECT REGEXP_SUBSTR(input_str, '[^,]+', 1, LEVEL) AS part
    FROM input_data
    CONNECT BY REGEXP_SUBSTR(input_str, '[^,]+', 1, LEVEL) IS NOT NULL
),
expanded AS (
    SELECT
        rownum rn,
        TO_NUMBER(REGEXP_SUBSTR(part, '[0-9]+')) AS start_num,
        CASE
            WHEN INSTR(part, '-') > 0
            THEN TO_NUMBER(REGEXP_SUBSTR(part, '[0-9]+$'))
            ELSE TO_NUMBER(REGEXP_SUBSTR(part, '[0-9]+'))
        END AS end_num
    FROM split_parts
)
--select * from expanded
SELECT distinct start_num + LEVEL - 1 AS result_number
FROM expanded
CONNECT BY LEVEL <= end_num - start_num + 1
AND PRIOR rn = rn  -- 防止笛卡爾積
AND PRIOR SYS_GUID() IS NOT NULL
--AND PRIOR dbms_random.random IS NOT NULL
ORDER BY result_number
/

SCOTT@book01p> @ ff1.sql "1-4, 5 ,7 ,9-11,1-4"
RESULT_NUMBER
-------------
            1
            2
            3
            4
            5
            7
            9
           10
           11
9 rows selected.

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.