1

I want to write a shell script to get the following output:

$ Enter String: a2b3

aabbb

I've used arrays within for loops, but it always fails to append two-digit values from the string, as a single element into the array. It always gets stored as two separate elements in the array.

The script used:

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 " "

The output I get for the same:

$ 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 

I need the value 12 to be stored as a single element num[0] rather than as two individual elements, num[0]=1, num[1]=2. Same with the value 20.

Please help me out here....thank you in advance.

  • 1
    This needs more details. Like, is there a number after every letter or is an input like `abc3` possible? If yes, what is the expected output for that? `abcabcabc` or `abccc`? – oguz ismail Mar 30 '20 at 15:16

3 Answers3

1

With 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]}}'

For example,

$ 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

To understand what gawk is doing, check out split function in the manual.


If you want to stick to bash, here is another way to do it:

#!/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 gets the sequences (letters,digits) from the string and mapfile generates an array from the output. For a20b30, you get an array with elements a20 and b30.

Then for each element of the array, you get the letters and digits and print the former digits times.

Output example:

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

I got the printf idea from this answer.

Quasímodo
  • 3,812
  • 14
  • 25
0

It's much easier to use a more advanced programming language, e.g. Perl:

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

But, if you you like torturing yourself in bash, keep a flag that tells you what you're parsing currently - either a string, or a number. Based on that, accumulate the characters in the correct array. Keep a separate index for the characters in the input and the element of the output, increase the latter when you start parsing a string after having parsed a number.

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
choroba
  • 231,213
  • 25
  • 204
  • 289
0

If you're reading the input character by character, you'll need to use a little state machine:

  • prev char was alpha, this char is alpha -> do something
  • prev char was alpha, this char is digit -> do something
  • etc

You might have better luck with using a regex

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

Unfortunately bash has no mechanism for "get me all the matches of this regex" so you're stuck with a while loop.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352