0

Let's say that I've Python dictionary text which i edited to be human readable. so it's now line by line as the following input.

Input

{"case":"0901","emailed":"yes","vote":1,"accepted":"no"},
{"case":"0908","emailed":"yes","vote":8,1"accepted":"yes"},
{"case":"0911","emailed":"no","vote":10,1"accepted":"yes"},
{"case":"0090","emailed":"yes","vote":3,1"accepted":"no"},

** ALL THE TEXT FILE IN THE PREVIOUS FORMAT **

So i would like to grep lines which include yes in first and no in second

So am expecting output to be like this

Output

{"case":"0901","emailed":"yes","vote":1,"accepted":"no"},
{"case":"0090","emailed":"yes","vote":3,1"accepted":"no"},

I were unable to find a way to grep by order of words yet.

And My second question is regarding my output ?

if i can use awk sum function in order to calculate the total of vote? which should be 4,1 from the output.

9
  • 3
    This looks like a typo: "vote":3,1"accepted":"no" -- whats that 1 doing in there? Dec 1, 2017 at 22:55
  • @glennjackman it's belong to the number itself which mean's that what between "" is the number of vote Dec 1, 2017 at 23:00
  • that what between "" - there are only case numbers between "" in your input (like "0901") Dec 1, 2017 at 23:09
  • 1
    this "vote":3,1 is definitely invalid notation to be a Python dictionary - it could not work Dec 1, 2017 at 23:11
  • @RomanPerekhrest thanks for correcting me, yes therefor for vote the numbers displayed like that :3,1 Dec 1, 2017 at 23:13

3 Answers 3

3

Check this:

Printing needed lines

awk -F'[,:]' ' 
$4 ~ "yes" && $8 ~ "no" {
    print;
}' input.txt

Output

{"case":"0901","emailed":"yes","vote":1,"accepted":"no"},
{"case":"0090","emailed":"yes","vote":3,1"accepted":"no"},

Calculating sum

awk -F'[,:]' ' 
$4 ~ "yes" && $8 ~ "no" {
    sum += $6"."$7;
}
END {
    print sum;
}' input.txt

Output

4.1
0
2

I've python dictionary text

The proper Python dictionary recovering/processing:

My message is: Python is Python ... you shouldn't garble its data structures

recover_dict.py script:

import sys, re, ast
with open(sys.argv[1], 'r') as f:
    items = ast.literal_eval(re.sub(r"(\d+),(\d+)", "\\1.\\2,", f.read().replace('\n','')))
    sum = 0
    for d in items:
        if d['emailed'] == 'yes' and d['accepted'] == 'no':
            sum += d['vote']
            print(d)
print(sum)

Usage:

python recover_dict.py file

The output:

{'case': '0901', 'vote': 1, 'accepted': 'no', 'emailed': 'yes'}
{'case': '0090', 'vote': 3.1, 'accepted': 'no', 'emailed': 'yes'}
4.1
0
1

Something like

grep 'yes.*no' yourfile \
    | sed -e 's/.*vote":\([0-9,]\+\).*/\1/g' -e 's/,/./g' \
    | paste -sd+ | bc

should work for you.

Explanation

  • grep 'yes.*no' yourfile

If you want to grep by order of words, but don't know what is in between, use .* to match any non-whitespace character repeated zero or more times. Output (with your input file):

$ grep 'yes.*no' inputfile
{"case":"0901","emailed":"yes","vote":1,"accepted":"no"},
{"case":"0090","emailed":"yes","vote":3,1"accepted":"no"}
  • sed -e 's/.*vote":\([0-9,]\+\).*/\1/g' -e 's/,/./g'

Match a number (digits and possibly ,), if preceded by ...vote": in the output of the grep above, and substitute , with .. Outputs

$ grep 'yes.*no' inputfile | sed -e 's/.*vote":\([0-9,]\+\).*/\1/g' -e 's/,/./g'
1.
3.1
  • paste -sd+

Substitutes the newline between your numbers with +, outputs:

$ grep 'yes.*no' inputfile | sed -e 's/.*vote":\([0-9,]\+\).*/\1/g' -e 's/,/./g' | paste -sd+
1.+3.1
  • bc

Executes the operation above (1.+3.1), outputs:

$ grep 'yes.*no' inputfile | sed -e 's/.*vote":\([0-9,]\+\).*/\1/g' -e 's/,/./g' | paste -sd+ | bc
4.1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .