【问题标题】:Bash split substringBash 拆分子字符串
【发布时间】:2011-10-30 12:50:50
【问题描述】:

我收到的数字变量有时是 2,有时是 3 位,例如“321”和“32”。我想在每个数字之间加上一个点。因此,如果我收到“32”,我必须回显“3.2”,如果收到“321”,我就回显“3.2.1”。

这就是我所做的:

S='321'
SL="${#S}" #string lentgh

n1=`echo $S | cut -c 1-1`
n2=`echo $S | cut -c 2-2`

if [ "$SL" -eq 2 ]; then
    echo $n1.$n2
elif  [ "$SL" -eq 3 ]; then
    n3=`echo $S | cut -c 3-3`
    echo $n1.$n2.$n3
else
    die 'Works only with 2 or 3 digits'
fi

我的问题是:有没有更短的方法来做同样的事情?


更新: 更短但仍然冗长:

SL="${#1}" #string lentgh
S=$1
if [ "$1" -eq 3 ]; then
    $n3=".${S:2:1}"
fi
if  [ "$SL" -lt 2 ] && [ "$SL" -gt 3 ]; then
    die 'Works only with 2 or 3 digits'
fi

echo "${S:0:1}.${S:1:1}$n3"

更新 1:

如果我包含 if 块,sed+regex 版本将与纯 bash 版本一样长:

SL="${#1}" #string lentgh
S=$1
N=$(echo $S | sed -r "s/([0-9])/\1./g")
echo ${N%%.}
if  [ "$SL" -lt 2 ] && [ "$SL" -gt 3 ]; then
    die 'Works only with 2 or 3 digits'
fi

或者,使用带有两个表达式的单行 sed+regex:

SL="${#1}" #string lentgh
echo $1 | sed -e 's/\([[:digit:]]\)/.\1/g' -e 's/^\.//'
if  [ "$SL" -lt 2 ] && [ "$SL" -gt 3 ]; then
    die 'Works only with 2 or 3 digits'
fi

谢谢。

【问题讨论】:

    标签: bash split substring


    【解决方案1】:
    S='321'
    perl -e "print join '.', split //, shift" "$S"
    

    【讨论】:

    • 但我不知道什么时候会是 2 位或 3 位数字……那怎么样?
    • 在 Perl 中,您可以使用正则表达式来验证这一点:$num =~ m/^\d{2,3}$/
    【解决方案2】:

    这是一个。这适用于任何字符串长度。

    #!/bin/bash
    
    #s is the string
    #fs is the final string
    
    echo "Enter string"
    read s
    
    n="${#s}"
    fs=""
    
    i=0
    for ((i=0; i<n; i++))
      do
       fs="$fs.${s:i:1}"
    done
    
    #find the length of the final string and
    #remove the leading '.' 
    
    n="${#fs}"
    fs="${fs:1}"
    
    echo "$fs"
    

    【讨论】:

    • 这很漂亮。如果我知道我总是会收到 2 或 3 位数怎么办?我猜你的代码可能会更短,对吗?
    • 我使用 bash 内置函数来实现这一点。在输入长度为 2 或 3 的情况下,您只需插入一个 if - else 就像 n 不是 32 进程将停止,否则它将继续循环。如果您只是想静态编码 2 或 3 长度的字符串,那么您可以简单地删除循环并手动编码 2 和 3 长度代码(正如您在问题中的代码中所做的那样)。或者使用其他人的其他解决方案。
    【解决方案3】:

    不是那么漂亮,但至少它很短:

    num=$(echo $S | sed -r "s/([0-9])/\1./g")
    echo ${num%%.}
    

    【讨论】:

    • 确实又丑又锋利。您能否就这段代码中真正发生的事情提供任何线索?我收到一个错误:“num: command not found”
    • 好吧,既然我已经包含了我忘记它可能真的可以工作的管道......对不起。 sed 命令会将任何数字替换为数字后跟一个句点(包括最后一个数字!)。这被保存到变量$num 中。由于最后一位数字后面是我们不想要的句点,因此我们使用 bash 的“删除后缀”扩展将其删除。
    • 注意:如果 sed 支持前瞻,则删除后缀将是不必要的,只需对正则表达式进行小修复以不匹配最后一个数字,例如 ([0-9])(?!$)。必须有一些转义,所以 bash 也不会扩展 !。
    • 嗯,实际上,当我这样总结它时,它对我也不起作用。只是echo $S | sed -r "s/([0-9])/\1./g" 有效...我会回来的,正如他们所说的
    • 哦,天哪……我很愚蠢。删除 = 周围的空格,一切都应该没问题。
    【解决方案4】:

    我也更喜欢 sed:

    echo 321 | sed -e 's/\([[:digit:]]\)/.\1/g' | cut -b2- -> 3.2.1

    echo 32 | sed -e 's/\([[:digit:]]\)/.\1/g' | cut -b2- -> 3.2

    或者没有剪裁它看起来像这样

    echo 321 | sed -e 's/\([[:digit:]]\)/.\1/g' -e 's/^\.//'
    

    【讨论】:

      猜你喜欢
      • 2013-01-15
      • 1970-01-01
      • 2014-04-23
      • 2021-10-23
      • 2016-05-30
      • 2013-08-08
      • 1970-01-01
      • 1970-01-01
      • 2020-09-06
      相关资源
      最近更新 更多