-2

I am trying to parse through a string of known format to obtain variables for speed and direction (basically recreating sscanf functionality), an example string shown below

s = 'speed: 100.0, direction[ 12 ]'

However, the square brackets after direction are causing me problems. I have tried

checker=re.search('speed: (?P<speed>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?), direction\[ (?P<direc>\d) \]',s)
print(f"[{checker['speed']},{checker['direc']}]")

adding \ before the square brackets as suggested here: https://stackoverflow.com/a/74477176/4879524

However, this is not working, and I am unsure how to proceed. If I remove the square brackets from the string it works fine, but I wish to avoid doing that if possible.

My regex knowledge is about 4 hours old so it may be a very simple fix. I cannot use parse module as an alternative sadly

WITH SQUARE BRACKETS - There is no match so...

TypeError: 'NoneType' object is not subscriptable

WITHOUT SQUARE BRACKETS

s = 'speed: 100.0, direction 12'

checker = re.search('speed: (?P<speed>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?), direction (?P<direc>\d)',s)
print(f"[{checker['speed']},{checker['direc']}]")

>>[100.0,1] # (yes I forgot the + when I wrote it out in stack so here's the answer without the +, you can see that's not causing my error)
Jack
  • 107
  • 7

3 Answers3

2

The bug has actually got nothing to do with the square brackets.

You need to replace this:

(?P<direc>\d)

With this:

(?P<direc>\d+)

So in other words, the full line of code becomes:

checker=re.search('speed: (?P<speed>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?), direction\[ (?P<direc>\d+) \]',s)

More specifically, your regex was only matching against one digit between the square brackets (e.g. "[ 1 ]"), rather than one-or-more digits between the square brackets (e.g. the actual example you gave above, of "[ 12 ]")

Tom Lord
  • 27,404
  • 4
  • 50
  • 77
  • Note for future: You said "If I remove the square brackets from the string it works fine", but you didn't actually give a code example of this happening -- doing so would been helpful for everyone involved :) – Tom Lord Mar 30 '23 at 12:12
  • Have edited it to include the results, you should be able to see the effect of the square brackets now, sorry I wrote this whilst eating my lunch and my stomach comes before my brain – Jack Mar 30 '23 at 12:14
  • @Jack Your **"WITHOUT SQUARE BRACKETS"** edit doesn't *just* remove the square brackets. You also removed the spaces around the number. That's why it matched. – Tom Lord Mar 30 '23 at 16:14
  • To be more precise, given this input string: `s = 'speed: 100.0, direction 12'`, that regex is matching up to the last character: `s = 'speed: 100.0, direction 1'`. It's not matching against the whole string. You can see this because the capture group for `direc` is `1` instead of `12`. – Tom Lord Mar 30 '23 at 16:16
1

You can use direction\[?\s*(?P<direc>\d+)\s*\]?:

checker=re.search('speed: (?P<speed>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?), direction\[?\s*(?P<direc>\d+)\s*\]?',s)
print(f"[{checker['speed']},{checker['direc']}]")

Output:

# s = 'speed: 100.0, direction[ 12 ]'
[100.0,12]

# s = 'speed: 100.0, direction 12'
[100.0,12]
Corralien
  • 109,409
  • 8
  • 28
  • 52
0

Here is a solution that finds (decimal) numbers in a string

import re
s = 'speed: 100.0, direction[ 12 ]'
# find (decimal) numbers in string. Only works if order is fixed
speed, direction = re.findall(r'\d+\.*\d*', s)

# output: 100.0, 12
speed = float(speed)  # cast to number
direction = float(direction)  # cast to number

Klops
  • 951
  • 6
  • 18