纯Bash替换捕获组

4

我有一个字符串示例:

test_string="13A6"

这些字符/数字可以是从 0 到 9 和从 A 到 F 的任意组合。

我希望得到以下输出:

1 3 A 6

我已经做到了这一点:
result=$(echo ${test_string} | sed 's/./& /g')

我希望不使用sed来完成它...我还有另一个解决方案,但我不太喜欢...有点 '脏' :S

[[ ${test_string} =~ ^([0-9A-F])([0-9A-F])([0-9A-F])([0-9A-F]) ]] && result="${BASH_REMATCH[1]} ${BASH_REMATCH[2]} ${BASH_REMATCH[3]} ${BASH_REMATCH[4]}"

如果可能的话,我希望使用纯Bash语法:result=${variable//pattern/replacement},但不确定如何在这种纯Bash语法中像sed一样引用匹配的字符本身,比如"&"。有哪位Bash专家可以帮忙吗? :)

1
使用循环:https://dev59.com/Wmoy5IYBdhLWcg3wN7e8#32545111 - Cyrus
2个回答

4
这个怎么样(不调用外部工具):
str="13A6"
[[ $str =~ ${str//?/(.)} ]]
printf '%s\n' "${BASH_REMATCH[*]:1}"

结果(不带尾随空格):

"1 3 A 6"

或者,如果你需要使用不同的分隔符:

[[ $str =~ ${str//?/(.)} ]]
( IFS=$'\n'; printf "%s\n" "${BASH_REMATCH[*]:1}")

或者,在一个函数中,IFS 可能是函数本地的:
divide(){ 
    [[ $1 =~ ${1//?/(.)} ]]
    local IFS=${2:-' '}
    printf '%s\n' "${BASH_REMATCH[*]:1}"
}

divide "13A6" "-"            # will output 1-3-A-6 in this example.

这是如何工作的:

这个功能的运作方式如下:

           ${str//?/(.)}              # Replace each character with "(.)".  
[[ $str =~               ]]           # Match the regex "(.)(.)(.) … …"  
                                      # capturing each character matched  
                                      # in the array "${BASH_REMATCH[@]}"  

printf '%s\n' "${BASH_REMATCH[*]:1}"  # Forget array index 0 and
                                      # convert the array to one string 
                                      # using the first character
                                      # of "$IFS" as separator
                                      # (no trailing separator). 

感谢 @chepner 推荐将数组中的 @ 更改为 *。这样可以避免使用临时数组或位置参数。


2
这非常好。但您无需覆盖位置参数,echo "\"${BASH_REMATCH[*]:1}\""同样有效,或者您可以使用捕获组填充数组:arr=( "${BASH_REMATCH[@]:1}" ) - chepner

0

我不知道它是否像你想要的那样纯粹:

test_string="13A6"
length=$( expr length "$test_string" )
s=""
for (( i=1;i<=${length};i++)) 
do
  c=$( expr substr "${test_string}" $i 1 )
  s=${s}" "$c
done
echo $s

结果:

1 3 A 6

或者使用 chepner 的帮助,纯粹地(不需要外部程序)。

test_string="13A6"
s=""
for ((i=0;i<${#test_string};i++))
do
  s=${s}" "${test_string:i:1}
done
echo $s

1
这里没有使用expr的理由;您可以使用${#test_string}获取字符串的长度,并且您可以使用${test_string:i:1}从字符串中获取单个字符。 - chepner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接