k n o w   t h y s e l f
1 2 3 4 5 6 7 8 9 0 1 2
0 0 0 0 0 0 0 0 0 1 1 1

In this project I try visualize strings as in the above.

IBAN Numbers

Counting the number of characters in a string is straight forward with wc

echo $iban_number | wc -c

Suppose we want to visualize the 24-character strings. We could define a bash function as follows

iban_ruler(){
	ruler=$(seq 24 | sed 's/$/%10/' | bc | xargs | tr -d ' ')
	echo $1
	echo $ruler
}

So now

$ iban_ruler SA0000000000000000000000
SA0000000000000000000000
123456789012345678901234

This is nice but is limited to 24 characters. Let’s make it more flexible:

string_ruler(){
        num_chars=$(echo $1 | wc -c)
        ruler=$(seq $num_chars | sed 's/$/%10/' | bc | xargs | tr -d ' ')
        echo $1
        echo $ruler
}

sed here is replacing the end of the sentence with %10 and piping the result to the calculator bc, the remainder will result from this, which is then piped to xargs to put the result on one line then the spaces are removed with tr. Now let’s try it

$ string_ruler 'aziz codes is the best blog in the universe'
aziz codes is the best blog in the universe 
12345678901234567890123456789012345678901234

This is nice but it’s not treating spaces correctly. Also, I want to show the another ruler that has the tens.

string_ruler4(){
	
	# print the input
	echo $1

	# insert spaces between characters in the input string
	# i.e. aziz becomes a z i z
	old_IFS=$IFS
	IFS=''
	data=$(echo -n "$1" | sed 's/\(.\)/\1 /g' )  # or sed 's/\B/ /g' ) 
	echo $data
	IFS=$old_IFS

        # calculate number of characters in the input string
	num_chars=$(echo -n "$1" | wc -c)
	
	# make a sequence of characters equal in length to the input string
	# pad single digits with zeros -> 01; 02; 03; etc
	# insert spaces between these 2-digit numbers -> 0 1; 0 2; 0 3 etc
	# the first field is the tens, the second field is ones (recognizable by awk)
	
	ones=$(seq $num_chars | sed 's/^\(.\)$/0\1/' | sed 's/\(.\)\(.\)/\1 \2/' | awk '{print $2}')
	
	tens=$(seq $num_chars | sed 's/^\(.\)$/0\1/' | sed 's/\(.\)\(.\)/\1 \2/' | awk '{print $1}')

	echo $ones
	echo $tens
}

You can see the result of this below.

$ string_ruler4 'know thyself'
know thyself
k n o w   t h y s e l f
1 2 3 4 5 6 7 8 9 0 1 2
0 0 0 0 0 0 0 0 0 1 1 1

With Bash Arrays

We can use arrays

string_ruler5(){

        # print the input 
        echo $1

        # make it space separated
        sep=$(echo $1 | sed 's/./& /g')

        # make an array
        arr=($sep)

        # make 
        for k in ${arr[@]}; do 
                echo $k
        done | nl | awk '{print int($1/10), int($1%10), $2}'
}       

The result of the above code is below

$ string_ruler5 knowthyself
knowthyself
0 1 k
0 2 n
0 3 o
0 4 w
0 5 t
0 6 h
0 7 y
0 8 s
0 9 e
1 0 l
1 1 f

improved to handles spaces below

string_ruler6(){
        input=$1
	letters=$(echo $input | sed 's/ /_/g' | sed 's/./& /g')
	arr=($letters)
	
	for a in "${arr[@]}"; do echo $a; done | xargs | sed 's/_/ /g'
	
	i=0
	for a in "${arr[@]}"; do
	    i=$(($i+1))
	    k=$(($i%10))
	    echo $k
	done | xargs

	i=0
	for a in "${arr[@]}"; do
	    i=$(($i+1))
	    j=$(($i/10))
	    echo $j
	done | xargs
}

Bonus: Other Attempts

Python is excellent at looping. A solution is below

import sys

arg=sys.argv[1]
print(arg)

numbered=[k for k in enumerate(arg)]

for n,a in numbered:
    print(a,end=' ')
print('')

for n,a in numbered:
    print(n%10,end=' ')
print('')

for n,a in numbered:
    print(n//10,end=' ')
print('')

Saved into numbered.py, then

$ python numbered.py 'know thyself'
know thyself
k n o w   t h y s e l f 
0 1 2 3 4 5 6 7 8 9 0 1 
0 0 0 0 0 0 0 0 0 0 1 1 

These attempts didn’t work but they were worth trying.

This one doesn’t work because brace expansion precedes command substitution.

string_ruler2(){																		  
        num_chars=$(echo $1 | wc -c)													  
        tens=$(echo $num_chars/10 | bc)													  
        ruler1=$(for k in {0..$tens}{1..9}; do echo ${k:1:1}; done | xargs | tr -d ' ')	  
        ruler2=$(for k in {0..$tens}{1..9}; do echo ${k:0:1}; done | xargs | tr -d ' ')	  
        echo $1																			  
        echo $ruler1																	  
        echo $ruler2																	  
} 

This one works but its lengthy and doesn’t treat spaces correctly.

string_ruler3(){
        num_chars=$(echo $1 | wc -c)
        tens=$(echo $num_chars/10 | bc)
	ruler1=$(
	    for i in $(seq 0 $tens); do
		for j in $(seq 10 | sed 's/.*\(.$\)/\1/g'); do		
			k=$i$j
			echo ${k:1:1} 
		done
	done | xargs | tr -d ' ')

	ruler2=$(
	for i in $(seq 0 $tens); do
		for j in $(seq 10 | sed 's/.*\(.$\)/\1/g'); do
			k=$i$j
			echo ${k:0:1} 
		done
	done | xargs | tr -d ' ')
	echo $1
        echo $ruler1
        echo $ruler2
}