user3054109
user3054109

Reputation:

Generate case range in bash

I want to input two and three digit numbers into a function and output a case range, i.e., input 33 and 66 and output 3[3-9] | [4-5][0-9] | 6[0-6] or input 33 and 666 and output 3[3-9] | [4-9][0-9] | [1-5][0-9][0-9] | 6[0-5][0-9] | 66[0-6]

What are some ideas as to how? Thanks!

Upvotes: 4

Views: 249

Answers (3)

user3054109
user3054109

Reputation:

Just want to share the final code: https://gist.github.com/zaydek/1627329f88c444f6d71d5cbc0cda616f :)

function enc {

    a=${1: -3:1}; b=${1: -2:1}; c=${1: -1}
    d=${2: -3:1}; e=${2: -2:1}; f=${2: -1}

    if   (( $[a] < $[d] )); then

        if   (( $b$c == 00 && $e$f == 99 )); then echo [$a-$d][0-9][0-9]
        elif (( $b$c == 00 )); then if (( $[a+1] < $d )); then echo [$a-$[d-1]][0-9][0-9] "|"; echo $(enc $[d]00 $d$e$f)
                                                          else echo $a[0-9][0-9] "|"; echo $(enc $[a+1]00 $d$e$f); fi

        else echo $(enc $a$b$c $[a]99) "|"; echo $(enc $[a+1]00 $d$e$f); fi

    elif (( $b < $e )); then

        if   (( $c == 0 && $f == 9 )); then echo $a[$b-$e][0-9]
        elif (( $c == 0 )); then if (( $[b+1] < $e )); then echo $a[$b-$[e-1]][0-9] "|"; echo $(enc $a$[e]0 $d$e$f)
                                                       else echo $a$b[0-9] "|"; echo $(enc $a$[e]0 $d$e$f); fi

        else echo $(enc $a$b$c $a$[b]9) "|"; echo $(enc $a$[b+1]0 $d$e$f); fi

    else

        if (( $c == $f )); then echo $a$b$c
        else echo $a$b[$c-$f]; fi; fi

}

function int {

    if [[ $1 = *.* ]]; then

        integer=${1%.*}
        decimal=${1#*.}

        if (( ${decimal:0:1} >= 5 )); then integer=$[integer+1]; fi

         echo $integer
    else echo $1; fi

}

function cse {

    minimum=$(int $(echo $1 $2 | awk '{ print ($1/$2)*( 90) }'))
    maximum=$(int $(echo $1 $2 | awk '{ print ($1/$2)*(110) }'))

    echo $(enc $minimum $maximum)

}

cse $1 $2

cse takes two inputs, converts them to decimals, and multiples each from a range, i.e., 90 and 110 for -10% and +10% error range, then passes off the minimum and maximum outputs as inputs to enc which is a recursive function that generates case range syntax (with syntax optimization).

Please note, bash does not appear to handle expressions for case ranges as expected or intended. Though, this code can be used to generate case ranges for all 2 to 3 digit numbers and then copied and pasted as inline code.

Upvotes: 1

riteshtch
riteshtch

Reputation: 8769

Here is the logic for 2 digit numbers:

#!/bin/bash
l=$1
h=$2

function get_nearest_upper_10th_mutlitple()
{
    v=$(($1+10))
    echo "${v%?}0"
}
function get_nearest_lower_10th_mutlitple()
{
    v=$1
    echo "${v%?}0"
}

temp="$(printf '%d' $l | wc -m)$(printf '%d' $h | wc -m)"
case $temp in
    11) echo "[$l-$h]"      ;;
    22|12)
        a=$([[ $(($l%10)) -eq 0 ]] && echo $l || echo $(($(get_nearest_upper_10th_mutlitple $l)-1)))
        if [[ $(printf '%d' $a | wc -m) -eq 1 ]]; then
            echo [$l-$a]
        else
            [[ $a -gt $l ]] && echo "${l%?}[${l#?}-${a#?}]" || echo $a
        fi

        b=$([[ $(($h%10)) -eq 0 ]] && echo $h || get_nearest_lower_10th_mutlitple $h)

        x=$((a+1))
        y=$((b-1))
        echo "[$(echo ${x%?}~${y%?} | sed 's/~/\n/g' | sort -n | uniq | paste -s -d '-')][${x#?}-${y#?}]"

        [[ $b -lt $h ]] && echo "${h%?}[${b#?}-${h#?}]" || echo $b
esac

Here are sample outputs:

$ ./script.bash 2 8
[2-8]
$ ./script.bash 2 6
[2-6]
$ ./script.bash 2 68
[2-9]
[1-5][0-9]
6[0-8]
$ ./script.bash 23 68
2[3-9]
[3-5][0-9]
6[0-8]
$ ./script.bash 23 99
2[3-9]
[3-8][0-9]
9[0-9]
$ ./script.bash 23 80
2[3-9]
[3-7][0-9]
80
$ ./script.bash 40 80
40
[4-7][1-9]
80
$ ./script.bash 40 80 | paste -s -d '|'
40|[4-7][1-9]|80
$ ./script.bash 35 55
3[5-9]
[4][0-9]
5[0-5]

You can use paste -s -d '|' to combine the individual ranges into a single ORed range.

You can use the existing functions which I've made to extend it for 3 digit numbers (I'll post the 3 digit version too after some time with different cases for 13 and 12).

Upvotes: 0

南山竹
南山竹

Reputation: 524

Here is the max 2 digits case for 0-99, I'd not used character's operations indeed I'd tried math arithmetic.

The following are some output:

./range.sh 1 39 -> 0[1-9] | [1-2][0-9] | 3[0-9]

./range.sh 21 49 -> 2[1-9] | [3-4][0-9]

./range.sh 33 66 -> 3[3-9] | [4-5][0-9] | 6[0-6]

./range.sh 33 99 -> 3[3-9] | [4-8][0-9] | 9[0-9]

Here is my code: range.sh, hope it can provide some help for you:

#!/bin/bash

LHS=$1
RHS=$2
B2=10

D2=$(echo "($RHS-$LHS)/$B2" | bc)
if [[ ${D2} -gt 0 ]]; then
  S2=(`seq $(echo "$LHS/$B2" | bc) $(echo "$LHS/$B2+$D2" | bc)`)
  #echo ${S2[@]}
  C=${#S2[@]}
  #echo $C

  L1=$(echo "$LHS%$B2" | bc)
  if [[ ${L1} -lt 9 ]]; then 
    L1R="[${L1}-9]"
  else
    L1R="9"
  fi

  R1=$(echo "$RHS%$B2" | bc)
  if [[ ${R1} -gt 0 ]]; then
    R1R="[0-${R1}]"
  else
    R1R="[0-9]"
  fi

  if [[ ${C} -gt 3 ]]; then
    echo -n $(echo "$LHS/$B2" | bc)$L1R
    echo -n " | "[${S2[1]}-${S2[$C-2]}][0-9]
    echo -n " | "${S2[$C-1]}$R1R
  elif [[ ${C} -eq 3 ]]; then
    if [[ ${S2[0]} -eq 0 ]]; then
      echo -n 0$L1R
    else
      echo -n $(echo "$LHS/$B2" | bc)$L1R
    fi
    echo -n " | "[${S2[1]}-${S2[$C-1]}][0-9]
  fi

else
  echo [$LHS-$RHS]
fi

echo

Upvotes: 0

Related Questions