Hex number sequence help

Need some help doing this ... with awk maybe

Input

0DF6
0DF7
0DF8
0DF9
0DFA
0DFB
0DFC
0DFD
0DFF
0E00
0E01
0E02
0E03
0E04
0E05
0E06
0E07
0E08
0E09
0E0C
0E0D
0E0E
0E0F
0E10
0E14

Ouput

 
0DF6:0DFD
0DFF:0E09
0E0C:0E10
0E14

Basically i need to shorten the list by printing all the ranges which are in sequence

Thanks

Try

$ awk 'NR==1{S=strtonum( "0x" $1 );P=$1}
         NR>1{K=strtonum( "0x" $1 );if((K - S) == 1){S=K;T=$1}else{print P":"T;P=$1;S=K}}END{if(P==$1){print P}}' file

0DF6:0DFD
0DFF:0E09
0E0C:0E10
0E14

Thanks .... ! this is only working for the example i gave ....

Like in another example

 
0DE1
0DE2
0DE3
0DE4
0DE5
0DE6
0DE7
0DE8
0DE9
0DEA
0DEB
0DEC

Output should be ... 0DE1:0DEC

or

 
 
0DD5
0DD6
0DD7
0DD8
0DDA
0DDB
0DDC
0DDD
0DDE
0DDF

Output should be ...

 
0DD5:0DD8 
0DDA:0DDF

Not getting this output ... also this is on solaris which does have GAWK needed for strtonum function

Sorry I've missed few steps.

now try

awk 'NR==1{S=strtonum( "0x" $1 );P=$1}
    NR>1{K=strtonum( "0x" $1 );if((K - S) == 1){S=K;T=$1}else{print P":"T;P=$1;S=K}}
    END{if(T==$1 && P!=$1){print P":"T}if(P==$1){print P}}' file
1 Like

Thanks again .... it works in all cases except this one ...

 
0DDB
0DDC
0DDD
0DDE
0DDF
0DE1
0DE4
0DE5
0DE6
0DE7
0DE8

The output should be

 
0DDB:0DDF
0DE1
0DE4:0DE8 

but its getting this ...

 
0DDB:0DDF
0DE1:0DDF
0DE4:0DE8 

Also ... can we pls get a "nawk" version of this ... thanks

What do you mean by 'nawk version'? A version which doesn't use GNU awk features like strtonum?

Right .... I wanted to use this on Solaris which does not have GAWK and thus cannot use strtonum function .... thx

strtonum is painful to try and do without. Fortunately the makers of GAWK were nice enough to make a nawk version for you.

nawk 'function mystrtonum(str, ret, chars, n, i, k, c)
     {
         if (str ~ /^0[0-7]*$/) {
             # octal
             n = length(str)
             ret = 0
             for (i = 1; i <= n; i++) {
                 c = substr(str, i, 1)
                 if ((k = index("01234567", c)) > 0)
                     k-- # adjust for 1-basing in awk
     
                 ret = ret * 8 + k
             }
         } else if (str ~ /^0[xX][[:xdigit:]]+/) {
             # hexadecimal
             str = substr(str, 3)    # lop off leading 0x
             n = length(str)
             ret = 0
             for (i = 1; i <= n; i++) {
                 c = substr(str, i, 1)
                 c = tolower(c)
                 if ((k = index("0123456789", c)) > 0)
                     k-- # adjust for 1-basing in awk
                 else if ((k = index("abcdef", c)) > 0)
                     k += 9
     
                 ret = ret * 16 + k
             }
         } else if (str ~ \
       /^[-+]?([0-9]+([.][0-9]*([Ee][0-9]+)?)?|([.][0-9]+([Ee][-+]?[0-9]+)?))$/) {
             # decimal number, possibly floating point
             ret = str + 0
         } else
             ret = "NOT-A-NUMBER"
     
         return ret
     }

     ...
     restofthecode
     ...'
1 Like

A portable solution (which is obviously less efficient):

f=input_filename

echo ibase=16 | cat - "$f" | bc | paste - "$f" | sed '1!p' | paste - - |
awk 'a=="" {a=$2} ($1+1 != $3) || NF == 2 {print a (a != $2 ? ":"$2 : ""); a=""}'

Tested with all your data samples and gives the correct result.

Regards,
Alister

1 Like

And a nawk version:

$ cat hex.awk

function mystrtonum(str, ret, chars, n, i, k, c)
     {
         if (str ~ /^0[0-7]*$/) {
             # octal
             n = length(str)
             ret = 0
             for (i = 1; i <= n; i++) {
                 c = substr(str, i, 1)
                 if ((k = index("01234567", c)) > 0)
                     k-- # adjust for 1-basing in awk

                 ret = ret * 8 + k
             }
         } else if (str ~ /^0[xX][[:xdigit:]]+/) {
             # hexadecimal
             str = substr(str, 3)    # lop off leading 0x
             n = length(str)
             ret = 0
             for (i = 1; i <= n; i++) {
                 c = substr(str, i, 1)
                 c = tolower(c)
                 if ((k = index("0123456789", c)) > 0)
                     k-- # adjust for 1-basing in awk
                 else if ((k = index("abcdef", c)) > 0)
                     k += 9

                 ret = ret * 16 + k
             }
         } else if (str ~ \
       /^[-+]?([0-9]+([.][0-9]*([Ee][0-9]+)?)?|([.][0-9]+([Ee][-+]?[0-9]+)?))$/) {
             # decimal number, possibly floating point
             ret = str + 0
         } else
             ret = "NOT-A-NUMBER"

         return ret
     }


P == "" {       P=strtonum("0x"$1); K=0;        next    }
(P+K+1) == strtonum("0x"$1) {   K++;    next    }

{
        if(!K)  printf("%04X\n", P);
        else    printf("%04X:%04X\n", P, P+K);
        P=strtonum("0x"$1);     K=0;
}

END {
        if(!K)  printf("%04X\n", P);
        else    printf("%04X:%04X\n", P, P+K);
}

$ nawk -f hex.awk data

0DDB:0DDF
0DE1
0DE4:0DE8

$

Both work .... fine ...

Thanks a lot Guys !!

No awk involved, but bash:

while read A
  do B=$((0x$A))
     [[ -z $L ]] && { printf "%04X" $B; L=B-1; }
     [[ $L+1 -eq $B ]] && K=0 || { [[ $K -eq 1 ]] && printf "\n%04X" $B || { printf ":%04X\n%04X" $L $B; K=1; }; }
     L=$B
  done < file
[[ $K -eq 0 ]] && printf ":%04X\n" $B || printf "\n"
0DF6:0DFD
0DFF:0E09
0E0C:0E10
0E14

0DE1:0DEC

0DDB:0DDF
0DE1
0DE4:0DE8
1 Like