【问题标题】:Handling two-digit numbers as a single element in arrays将两位数作为数组中的单个元素处理
【发布时间】:2020-03-30 14:12:12
【问题描述】:

我想写一个shell脚本来得到以下输出:

$ Enter String: a2b3

aabbb

我在for 循环中使用了数组,但它总是无法将字符串中的两位数值作为单个元素附加到数组中。它总是作为两个单独的元素存储在数组中。

使用的脚本:

echo "Enter your alphanumeric string: "
read a
n=${#a}

for (( i=0;i<n;i++ ))
do
string[i]=${a:i:1}

if [[ ${string[i]} =~ [a-zA-Z] ]]
then
alpha+=("${string[i]}")
elif [[ ${string[i]} =~ [0-9] ]]
then

if [[ ${string[i+1]} =~ [0-9] ]]
then
num+=${string[i]}${string[i+1]}
elif ! [[ ${string[i+1]} =~ [0-9] ]]
then
num+=("${string[i]}")
fi

fi
done

n=${#num[*]}
for (( i=0;i<n;i++ ))
do
echo num[$i] = ${num[i]}
done

n=${#alpha[*]}
for (( i=0;i<n;i++ ))
do
echo alpha[$i] = ${alpha[i]}
done

n=${#alpha[*]}
for (( i=0;i<n;i++ ))
do
y=${num[i]}
for (( j=0;j<y;j++ ))
do
echo -ne ${alpha[i]}
done
done
echo " "

我得到相同的输出:

$ sh Q1.sh
Enter your alphanumeric string: 
a12b20
num[0] = 1
num[1] = 2
num[2] = 2
num[3] = 0
alpha[0] = a
alpha[1] = b
abb 

我需要将值12 存储为单个元素num[0],而不是作为两个单独的元素num[0]=1num[1]=2。与值20 相同。

请帮帮我....提前谢谢您。

【问题讨论】:

  • 这需要更多细节。比如,每个字母后面是否有一个数字,或者像abc3 这样的输入是否可能?如果是,那么预期的输出是什么? abcabcabcabccc?

标签: arrays linux bash shell


【解决方案1】:

使用 GNU awk:

gawk '{n=split($0,a,/[0-9]+/,s);for(i=1;i<=n;i++){for(j=1;j<=s[i];j++)printf a[i]}}'

例如,

$ echo "A10b2"|gawk '{n=split($0,a,/[0-9]+/,s);for(i=1;i<=n;i++){for(j=1;j<=s[i];j++)printf a[i]}}'
AAAAAAAAAAbb

要了解gawk 在做什么,请查看the manual 中的拆分功能。


如果你想坚持使用 bash,这里有另一种方法:

#!/bin/bash
read -p "Enter your alphanumeric string: " a
mapfile -t array < <(echo "$a"|grep -Eo "[a-zA-Z]+[0-9]+")
for x in "${array[@]}"; do
    letters=${x%%[0-9]*}
    digits=${x##*[a-z]}
    printf "%0.s$letters" $(seq 1 $digits)
done
echo

grep 从字符串中获取序列(字母、数字),mapfile 从输出中生成一个数组。对于a20b30,您将获得一个包含元素a20b30 的数组。

然后对于数组的每个元素,您将获得 lettersdigits 并打印前 digits 次。

输出示例:

$ bash alpha.sh
Enter your alphanumeric string: x3zx10n2
xxxzxzxzxzxzxzxzxzxzxzxnn

我从this answer 那里得到了printf 的想法。

【讨论】:

    【解决方案2】:

    如果您正在逐个字符地读取输入,则需要使用一个小型状态机:

    • prev char 是 alpha,这个 char 是 alpha -> 做点什么
    • prev char 是 alpha,这个 char 是 digit -> 做点什么

    使用正则表达式可能会更好

    while [[ $input =~ ([[:alpha:]])([[:digit:]]+) ]]; do
        char=${BASH_REMATCH[1]}
        num=${BASH_REMATCH[2]}
        input_prefix=${input%%${BASH_REMATCH[0]}*}
        input_suffix=${input#*${BASH_REMATCH[0]}}
        # then reconstruct $input using those pieces
    done
    

    不幸的是,bash 没有“让我得到这个正则表达式的所有匹配项”的机制,所以你被困在一个 while 循环中。

    【讨论】:

      【解决方案3】:

      使用更高级的编程语言要容易得多,例如Perl:

      $ perl -we 'print $1, $2 x $3
                      while $ARGV[0] =~ /([^0-9]*)([^0-9])([0-9]+)/g
          ' a1b1c3de11
      abcccdeeeeeeeeeee
      

      但是,如果您喜欢在 bash 中折磨自己,请保留一个标志,告诉您当前正在解析什么 - 字符串或数字。在此基础上,将字符累积到正确的数组中。为输入中的字符和输出的元素保留一个单独的索引,当您在解析数字后开始解析字符串时增加后者。

      current=string
      
      j=0
      
      for (( i=0;i<n;i++ )) ; do
          if [[ ${a:i:1} == [0-9] ]] ; then
              [[ $current == string ]]
              current=num
              num[j]+=${a:i:1}
          else
              [[ $current == num ]] && (( ++j ))
              current=string
              alpha[j]+=${a:i:1}
          fi
      done
      

      【讨论】:

        猜你喜欢
        • 2013-11-08
        • 1970-01-01
        • 2014-08-06
        • 2013-07-05
        • 1970-01-01
        • 2020-06-21
        • 2010-12-31
        • 1970-01-01
        • 2013-10-31
        相关资源
        最近更新 更多