Regex for matching a floating point number of fixed width

Viewed 99

Short

I am looking for a regular expression capturing the longest possible floating point number up to n characters. It should be able to directly replace C format specifiers like "%5f" in C's scanf function.

Examples

For n=5, we want to capture

string       captured group
123        ->   123
1.23       ->   1.23
123456     ->   12345
+12.34     ->   +12.3
-12.34     ->   -12.3
1.2-3      ->   1.2
1.2.3.4    ->   1.2

Background

The above behaviour is similar to C's "sscanf" function with "%5f" as format specifier. From the manpage: "Reading of characters stops either when this maximum [n in our case] is reached or when a nonmatching character is found, whichever happens first." I am trying to build a python analog to scanf. There are existing projects like this one, but without support for the maximum field width.

My approach

My question is somewhat similar to this question.

I tried the following regex: ((?=[+-]?\d+(?:\.\d*)?)[\d\.+-]{1,5})

It consist of a lookahead, checking the format of the number, and a following character class with an interval, restricting the length of the captured group. The problem lies in the last example above, where the lookahead correctly matches only the first part of the string, but the interval extends up to the trailing '-3'. Do you have any suggestions? Can we create a regex, where the interval refers only to the characters matched by the lookahead?

Thank you very much in advance!

2 Answers

Well, you could possibly get along with just

^(?:-[\d.]{1,4}|[\d.]{1,5})

if your column only has these strings. See a demo on regex101.com.
Note, that this expression would also allow sth. like ...5. If you have these sort of strings, you'd need to make the expression more strict.

You can use

^[+-]?\d+(?:\.\d*)?(?<!.{6})
^[+-]?\d+(?:\.\d+)?(?<!.{6})

See the regex demo. Details:

  • ^ - start of string
  • [+-]? - an optional + or -
  • \d+ - one or more digits
  • (?:\.\d*)? - an optional occurrence of . and zero or more digits (one or more digits if you use \d+)
  • (?<!.{6}) - a negative lookbehind that fails the match if there are six chars other than line break chars immediately to the left of the current position.
Related