If your objective is to determine if a string has the correct form, and not necessarily to use a regex applied to the entire string to make that determination, you could perform two steps, employing the following regular expressions:
r1 = /(?<!,), ?/
r2 = /^\d+(?:\.\d{,2})?$/
The steps are:
- use
r1
to split the string into one or more substrings
- determine if all substrings match
r2
r1
reads, "match a comma followed by at most one space and not preceded by a comma.
r2
reads, "match one or more digits at the beginning of the string, optionally followed by a decimal point then 0, 1 or 2 digits, followed by the end of the string".
In Ruby, for example, the following obtains:
arr =<<~END.split("\n")
1.23
1
1,
1.2,4
1.23, 4
1.23, 4,
1, 2.34
1, 2.34
1,,
1.234
END
#=> ["1.23", "1", "1,", "1.2,4", "1.23, 4", "1.23, 4,", "1, 2.34",
# "1, 2.34", "1,,", "1.234"]
arr.each do |s|
a = s.split r1
result = a.all? { |t| t.match? r2 } ? "(Match)" : "(No match)"
puts "%-9s: %-14s %s" % [s, a.inspect, result]
end
string array match?
---------------------------------
1.23 : ["1.23"] (Match)
1 : ["1"] (Match)
1, : ["1"] (Match)
1.2,4 : ["1.2", "4"] (Match)
1.23, 4 : ["1.23", "4"] (Match)
1.23, 4, : ["1.23", "4"] (Match)
1, 2.34 : ["1", "2.34"] (Match)
1, 2.34 : ["1", " 2.34"] (No match)
1,, : ["1", ","] (No match)
1.234 : ["1.234"] (No match)
An important advantage of this approach is that testing is much easier than testing a single regular expression against the entire string, as r1
and r2
can be tested separately. This approach may also be more easily adaptable to changing requirements in future.