Counting string occurrences in Python

Apr 10, 2016 12 Replies

Background: I am trying to write a simple piece of code which interfaces with gpsd to return the number of GPS satellites visible and the number which gpsd is actually using. This is at the limits of my capabilities, but I have got as far as getting a string in Python which has the information embedded.



For each satellite, there is a string pair (excuse my terminology - I don't know Python) which is either u'used': False or u'used' True. I would like the program to return two values: the total number of satellites visible (the number of u'used' strings) and the total number used (the number of u'used': True strings). Is there a nice easy way to do this?



(Were this FreePascal/Lazarus I guess it would be easy, or if I knew more JSON!).


Here the full report:



[, , , , , , , , , , , , , , , ]
Thanks, David Web: http://www.satsignal.eu

You should just try to google for your subject line. The second hit gave me this:

formatting link

2

Great - and it seems it's a JSON encoded string so rather than doing any string processing on it why not decode it using the json module (loads method) which will turn it into a list of dicts which you can loop through something roughly like this.

import json

sats = json.loads(gps_str) total_sats = len(sats) used_sats = 0 for sat in sats: if sat['used']: used_sats = used_sats + 1

Steve O'Hara-Smith | Directable Mirror Arrays C:>WIN | A better way to focus the sun The computer obeys and wins. | licences available see You lose and Bill collects. | http://www.sohara.org/

Thanks, Stefan. I had searched, and tried a function such as you suggest, but unfortunately it returned 0 when searching for either "used" or "True". There were no compiler errors, but I don't know Python well enough to know where I'm going wrong.

Cheers, David Web: http://www.satsignal.eu

On 10/04/2016 11:15, Ahem A Rivet's Shot wrote: []

Thanks, Ahem, I appreciate your help. I did try that but it seems not to work for my data at least. Here's the error message and the program:

Traceback (most recent call last): File "gpsdRead.py", line 22, in sats = json.loads (report.satellites) File "/usr/lib/python2.7/json/__init__.py", line 338, in loads return _default_decoder.decode(s) File "/usr/lib/python2.7/json/decoder.py", line 366, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) TypeError: expected string or buffer ===========================

import gps import json from collections import Counter

# Listen on port 2947 (gpsd) of localhost session = gps.gps("localhost", "2947") session.stream(gps.WATCH_ENABLE | gps.WATCH_NEWSTYLE)

while True: try: report = session.next() # Wait for a 'SKY' report and display the current time # To see all report data, uncomment the line below # print report if report['class'] == 'SKY': # print report session = None if hasattr(report, 'satellites'): # print report.satellites # print report.satellites.count("used") # print report.satellites.count("True") sats = json.loads (report.satellites) total_sats = len (sats) used_sats = 0 for sat in sats: if sat['used']: used_sats = used_sats + 1 print total_sats print used_sats session = None quit() except KeyError: pass except KeyboardInterrupt: quit() except StopIteration: session = None print "GPSD has terminated"

Cheers, David Web: http://www.satsignal.eu

Show us the code you wrote, then we *might* have some chance of suggesting what's wrong.

(... and Python isn't a compiler)

Chris Green

On Sun, 10 Apr 2016 15:17:37 +0100, David Taylor declaimed the following:

From your earlier post:

How did you produce that "report". I'm not up on JSON myself, but those structures don't seem valid. With them in place I get

ValueError: No JSON object could be decoded

Removing them got me to

ValueError: Expecting property name: line 2 column 3 (char 3)

After much trial and error I managed to get

report = """ [ {"ss": 24, "el": 10, "PRN": 67, "az": 130, "used":"False"}, {"ss": 30, "el": 63, "PRN": 68, "az": 130, "used":"False"}, {"ss": 14, "el": 59, "PRN": 69, "az": 309, "used":"False"}, {"ss": 12, "el": 73, "PRN": 78, "az": 118, "used": "False"}, {"ss": 26, "el": 39, "PRN": 79, "az": 190, "used":"False"}, {"ss": 17, "el": 18, "PRN": 85, "az": 315, "used":"False"}, {"ss": 31, "el": 26, "PRN": 136, "az": 170, "used":"True"}, {"ss": 30, "el": 23, "PRN": 28, "az": 137, "used": "True"}, {"ss": 38, "el": 66, "PRN": 30, "az": 92, "used":"True"}, {"ss": 31, "el": 40, "PRN": 20, "az": 297, "used":"True"}, {"ss": 27, "el": 15, "PRN": 21, "az": 327, "used":"True"}, {"ss": 11, "el": 8, "PRN": 27, "az": 23, "used":"False"}, {"ss": 32, "el": 66, "PRN": 5, "az": 212, "used": "True"}, {"ss": 27, "el": 40, "PRN": 7, "az": 61, "used": "True"}, {"ss": 17, "el": 4, "PRN": 9, "az": 96, "used":"False"}, {"ss": 38, "el": 54, "PRN": 13, "az": 269, "used":"True"} ] """ to feed to the loader. The order has changed as I was cut&pasting from one record up to the full set. Note that I had to:

1) remove the 2) remove the u' leaving just the ' (actually, I also ended up changing all ' to ") 3) True and False had to be quoted; without the quotes I got errors.

How you massage your input data to fit is another matter...

-=-=-=-=- import json

report = """ [ {"ss": 24, "el": 10, "PRN": 67, "az": 130, "used":"False"}, {"ss": 30, "el": 63, "PRN": 68, "az": 130, "used":"False"}, {"ss": 14, "el": 59, "PRN": 69, "az": 309, "used":"False"}, {"ss": 12, "el": 73, "PRN": 78, "az": 118, "used": "False"}, {"ss": 26, "el": 39, "PRN": 79, "az": 190, "used":"False"}, {"ss": 17, "el": 18, "PRN": 85, "az": 315, "used":"False"}, {"ss": 31, "el": 26, "PRN": 136, "az": 170, "used":"True"}, {"ss": 30, "el": 23, "PRN": 28, "az": 137, "used": "True"}, {"ss": 38, "el": 66, "PRN": 30, "az": 92, "used":"True"}, {"ss": 31, "el": 40, "PRN": 20, "az": 297, "used":"True"}, {"ss": 27, "el": 15, "PRN": 21, "az": 327, "used":"True"}, {"ss": 11, "el": 8, "PRN": 27, "az": 23, "used":"False"}, {"ss": 32, "el": 66, "PRN": 5, "az": 212, "used": "True"}, {"ss": 27, "el": 40, "PRN": 7, "az": 61, "used": "True"}, {"ss": 17, "el": 4, "PRN": 9, "az": 96, "used":"False"}, {"ss": 38, "el": 54, "PRN": 13, "az": 269, "used":"True"} ] """

result = json.loads(report) print "Reported PRNs: ", len(result) print "Visible PRNs: ", len([rec for rec in result if rec[u"used"] == u"True"])

-=-=-=-=-=-

Reported PRNs: 16 Visible PRNs: 8

Wulfraed Dennis Lee Bieber AF6VN wlfraed@ix.netcom.com HTTP://wlfraed.home.netcom.com/

There are newsgroups for python too, which should be used in preference unless your problem is specific to the Raspberry Pi, which in this case it isn't.

---druck

You're right, of course, about the newsgroups, although in this case the issues /may/ be RPi-specific since it has not got the up-to-date versions of gpsd. I'm more tending towards writing my own program in Pascal (Lazarus) as the delay in getting the required message (SKY) is annoying me!

Cheers, David Web: http://www.satsignal.eu

Ah I see it's already structured and what you posted was the result of python turning it into a string to print it - then I was trying to get you to turn it back into what you started with :)

Life is simpler for you. Ignore this bit:

In here use report.satellites where I have sats.

Or you can use the more compact way of counting suggested by Dennis - I wouldn't because it allocates an array that isn't used for anything but counting it's length.

One more thing this:

Would be nicer as:

if 'satellites' in report:

Steve O'Hara-Smith | Directable Mirror Arrays C:>WIN | A better way to focus the sun The computer obeys and wins. | licences available see You lose and Bill collects. | http://www.sohara.org/

Yes, comp.lang.python is a very friendly and helpful newsgroup.

Chris Green

Thanks for that, Steve. It's now written up here:

formatting link

and your help is acknowledged. If anyone else feels they should be acknowledged please let me know.

Cheers, David Web: http://www.satsignal.eu

Thanks for everyone's help with this. Whilst I did get a working solution with Python, I found a much quick way was to write a small piece of C. For those interested, please see:

formatting link

Cheers, David Web: http://www.satsignal.eu

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required