Searching for pattern and printing the count

Viewed 106

I have input table as below

module      input        output    type           func
AOIO        A1,A2,B       Z         comb        ((!A1+!A2) B)
AN2         A1,A2         ZN        comb        (A1 A2)
AIO         A1,A2,A3      Z          comb       ((A1 A2)+A3)
NOR         A1,A2 ,B       Z        comb       (!((A1 A2)+B))
BUF         I             Q          seq         I
CLK         I             QN         seq        IN
BND     
INV         IN            Z           comb      (!I)      

I want above table to display in below format

module      input        output    type           func                 path
AOIO        A1,A2,B       Z         comb        ((!A1+!A2) B)           3
AN2         A1,A2         ZN        comb        (A1 A2)                 1
AIO         A1,A2,A3      Z          comb       ((A1 A2)+A3)            2
NOR         A1,A2 ,B       Z        comb       (!((A1 A2)+B))           3
BUF         I             Q          seq         I                      1
CLK         I             QN         seq        IN                      1
BND                                                                     0
INV         IN            Z           comb      (!I)                    1

The logic to get path is

count the opening bracket '('.

If ( ends with ! then assign path as count+1 as in AO case. If it doesn't have ! then assign path as count i.e only no.of opening bracket (AN,AI case). If it does not have opening bracket assign path as 1 (BUF,CLK case). If it doesn't have func, assign path as 0(BND case). If ! is present between opening brackets ( then ignore ! and count the number of opening brackets and assign it to path (as in NOR case). And whenever there is (!I) present in func, assign path as 1 always.

Can anybody help me building logic for this. I can count for ( using below code and gets value of no. of ( And then can check for above conditions using

sed 's/[^(]//g'  file  | awk '{ print length}  |  awk '{ if ($2~/^(*!/ ) print $3 length+1 ; elseif($2~/^( / ) print $3 length; elseif ($2 !~ /(/ print $3 "1"; elseif ($2~/(!I)/ ) print $3 "1"

But here in code i am not getting count of '( ' and getting error. And I am not getting logic how can i count opening bracket if '!' is in between.

2 Answers

You may try this awk as well:

cat cpath.awk
BEGIN {
    FS = " {3,}"
}
NR == 1 {
   printf "%-30s %s\n", $0, "path"
   next
}
{
    n = 0

    if ($2 ~ /!I|^[^(]+$/)
       n = 1
    else if (match($2, /^\(+![^(]/))
       n = RLENGTH -1
    else if (match($2, /^\([!(]*/)) {
       s = substr($2, 1, RLENGTH)
       n = gsub(/!$|\(/, "", s)
    }

    printf "%-30s %s\n", $0, n
}

Then ute it as:

awk -f cpath.awk file
module      input         output   type     func             path
AOIO        A1,A2,B       Z        comb     ((!A1+!A2) B)    3
AN2         A1,A2         ZN       comb     (A1 A2)          1
AIO         A1,A2,A3      Z        comb     ((A1 A2)+A3)     2
NOR         A1,A2 ,B      Z        comb     (!((A1 A2)+B))   3
BUF         I             Q        seq      I                1
CLK         I             QN       seq      IN               1
BND                                                          0
INV         IN            Z        comb     (!I)             1

EDIT: Adding solution since OP's samples are changed.

awk '
FNR==1{
  OFS="\t"
  print $0,"path"
  next
}
{
  line=$0
  if($0~/!I/){
     print $0,1
     next
  }
  sub(/[^(]*/,"")
  sub(/[a-zA-Z0-9].*/,"")
  if($0~/!$/){
     print line,length($0)
  }
  else if(!NF){
     print line,length($0)+1
  }
  else if($0 ~ /!/ && $0 !~ /!$/){
     print line,length($0)-1
  }
  else{
     print line,length($0)
  }
}' Input_file | column  -t -s $'\t'

Output will be as follows.

module      input        output    type           func         path
AOIO        A1,A2,B       Z         comb        ((!A1+!A2) B)  3
AN2         A1,A2         ZN        comb        (A1 A2)        1
AIO         A1,A2,A3      Z          comb       ((A1 A2)+A3)   2
NOR         A1,A2 ,B       Z        comb       (!((A1 A2)+B))  3
BUF         I             Q          seq         I             1
CLK         I             QN         seq        IN             1
BND                                                            1
INV         IN            Z           comb      (!I)           1


Could you please try following, based on your shown samples only in GNU awk.

awk '
FNR==1{
  OFS="\t"
  print $0,"path"
  next
}
{
  line=$0
  if($0~/!I/){
     print $0,1
     next
  }
  $1=""
  sub(/[^\t]*\t+/,"")
  sub(/[a-zA-Z0-9].*/,"")
  if($0~/!$/){
     print line,length($0)
  }
  else if(!NF){
     print line,length($0)+1
  }
  else if($0 ~ /!/ && $0 !~ /!$/){
     print line,length($0)-1
  }
  else{
     print line,length($0)
  }
}' Input_file | column  -t -s $'\t'

Output will be as follows.

module     func            path
AO         ((!A1+!A2) B)   3
AN         (A1 A2)         1
AI         ((A1 A2)+A3)    2
NOR        (!((A1 A2)+B))  3
BUF         I              1
CLK         IQ             1
BND                        0
INV        (!I)            1

Explanation: Adding detailed explanation for above.

awk '                                   ##Starting awk program from here.
FNR==1{                                 ##Checking condition if this is first line then do following.
  OFS="\t"                              ##Setting OFS as tab here.
  print $0,"path"                       ##Printing current line and path string here.
  next                                  ##next will skip all further statements from here.
}
{
  line=$0                               ##Setting variable line to current line.
  if($0~/!I/){                          ##Checking condition if line is equal to !I then do following.
     print $0,1                         ##Printing current line and 1 here.
     next                               ##next will skip all further statements from here.
  }
  $1=""                                 ##nullifying first field here.
  sub(/[^\t]*\t+/,"")                   ##Substituting everything till tab and tab occurrences with NULL here.
  sub(/[a-zA-Z0-9].*/,"")               ##Substituting everything till last in current line.
  if($0~/!$/){                          ##Checking if line do not end with ! then do following.
     print line,length($0)              ##Printing line and length of current line.
  }
  else if(!NF){                         ##else if number of fields is NULL then do following.
     print line,length($0)+1            ##Printing line and length of current line +1 here.
  }
  else if($0 ~ /!/ && $0 !~ /!$/){      ##else if line is NOT equal to ! AND not ending with !
     print line,length($0)-1            ##Printing line and length of current line-1 here.
  }
  else{                                 ##else do following.
     print line,length($0)              ##Printing line and length of current line.
  }
}' Input_file | column  -t -s $'\t'     ##Passing awk output to column command to separate it tab wise.
Related