简体   繁体   中英

Validate comma separated list of numbers with regex

This cases should match:

1.23
1
1,
1.2,4
1.23, 4
1.23, 4,
1, 2.34
1.

This cases should not:

1,,
1.234

So there can be trailing comma or dot, zero or one space after comma. Numbers can be integers or floats with up to two fractions.

I've made this regex, but it fails on numbers with more than two fractions: https://regex101.com/r/CLTP2j/75

/^(?:\d+(?:\.[\d{1,2}]*)?|\.[\d{1,2}]+)(?:,[\s]?(?:\d+(?:\.[\d{1,2}]*)?|\.[\d{1,2}]+))*$/

Use the following regex:

^\d+(?:\.\d{0,2})?(?:,\s*\d+(?:\.\d{0,2})?)*,?$

Demo

Rather than giving the typical verbose (and illegible) full breakdown of the pattern I used, I will instead explain a simpler requirement. Let's say you wanted to validate a CSV list of capital letters, eg

A,B,C

The pattern you would use is:

^[A-Z](?:,[A-Z])*,?$

Note that the term on the right says to allow zero or more additions of comma followed by another letter. Your requirement also allows a trailing comma, so the above pattern includes that too.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM