5

I need some help.
I have to construct a regex for angularjs ng-pattern attribute. The regex has to validate a text, not each line or some pieces. The text has to contains some amounts with exactly 2 decimals and each amount should be entered in the new line. Also, spaces are accepted before and after each amount. If one line contains 2 amount then the entire text is not valid.

For example this text is valid because each amount is entered in the new line:

123.34 
12345.56
2.54

This example is not valid because one line contains 2 amounts:

12.43
123.32 2345.54
124.43

This example is not valid because one amount does not contains 2 decimal(each amounts has to be with exactly 2 decimals):

123
123.43
123.65

My best try is ^(([0-9]+[.][0-9]{2})\s*)+$ and it can be tested here. But my regex it's not enough because it accept text with multiple amounts in the same line.

Thanks

5
  • Can there be leading / trailing spaces on the lines? Try ^\d+\.\d{2}(?:\r?\n\d+\.\d{2})*$ if not, see regex101.com/r/E5l3SB/1 demo. Commented Feb 2, 2018 at 9:19
  • Yes, leading / trailing spaces are accepted. Commented Feb 2, 2018 at 9:21
  • 1
    Then try /^[^\S\r\n]*\d+\.\d{2}(?:[^\S\r\n]*\r?\n[^\S\r\n]*\d+\.\d{2})*[^\S\r\n]*$/. Commented Feb 2, 2018 at 9:25
  • Thank you WiktorStribiżew, it is perfect. Commented Feb 2, 2018 at 9:49
  • I posted the answer explaining the regex and explained it together with how you may tweak it and how it interacts with ng-trim. Commented Feb 2, 2018 at 10:07

4 Answers 4

6

Regex is not my strong point, so there may be a much simpler way to do this, but this does meet your requirements:

^(([^\S\r\n]*[0-9]+[.][0-9]{2}[^\S\r\n]*)\n)*(([^\S\r\n]*[0-9]+[.][0-9]{2}[^\S\r\n]*))$

Effectively what it does is ensure that the last line (without a newline character at the end) is always present, but also allows for optional lines before that which end with a newline (\n).

We also use the [^\S\r\n] part in place of \s to ensure that it checks for whitespace characters excluding newline, as the newline is what causes an issue with validating multiple values on the same line.

Here is a working example

Sign up to request clarification or add additional context in comments.

7 Comments

This does not validate the input if one line contains tab (\t). Except that, it is a good regex for my needs. Thanks
@GryphG: You didn't mention that in your question though... so, is it spaces and tabs? Or something else you haven't mentioned either? I have updated the answer to support tabs
That was my mistake. Now i mentioned everything.
The [ \t] still does not match lots of other horzontal whitespace (like hard space). Besides, quantifying the left part makes the regex perform slightly worse compared to the variation where the right part closer to $ is quantified.
@WiktorStribiżew: OP only asked for spaces, and then subsequently tabs. OP has now commented those are the only 2 requirements
|
3

You may use

ng-pattern="/^[^\S\r\n]*\d+\.\d{2}(?:[^\S\r\n]*\r?\n[^\S\r\n]*\d+\.\d{2})*[^\S\r\n]*$/"

See the regex demo.

Or, since angular trims the input before sending it to the regex engine by default (if you have no ng-trim or if you have ng-trim="true"), you may also use

ng-pattern="/^\d+\.\d{2}(?:[^\S\r\n]*\r?\n[^\S\r\n]*\d+\.\d{2})*$/"

Or, if you want to make sure there are no empty lines at start/end, use the first regex with ng-trim="false".

Pattern details

  • ^ - start of string
  • [^\S\r\n]* - any 0+ horizontal whitespaces
  • \d+ - 1 or more digits
  • \. - a . char
  • \d{2} - 2 digits
  • (?: - start of a non-capturing group matching...
    • [^\S\r\n]* - any 0+ horizontal whitespaces
    • \r?\n - a line break sequence
    • [^\S\r\n]*\d+\.\d{2} - any 0+ horizontal whitespaces, 1+ digits, . and 2 digits
  • )* - ... zero or more times
  • [^\S\r\n]* - any 0+ horizontal whitespaces
  • $ - end of string.

Comments

1

add the multiline flag /m to be able to anchor ^ to the start of each line

/^([0-9]+[.][0-9]{2})\s*$/gm

e.g. https://regex101.com/r/XMTSok/4

2 Comments

if also want leading spaces, you can use \s* on front as well, since having modifier/flag /m would make it multiline anyway
This does not validate the input as a single block of text as per the requirements
1

the problem is that \s matches also spaces use [\r\n] instead to match newlines and cariage return.

EDIT my first post mentioned \R but it's PCRE specific.

EDIT following comments to accept also space at the end of line

^(([0-9]+[.][0-9]{2}) *(?:\r?\n|$))+$

regex101

2 Comments

This doesn't seem to validate the whole text. For example, put a new line at the end that is invalid number, like 12.3... the whole thing should be a non-match. Also, OP want to accept spaces at the start of the lines too
fixed, the last $ was wrongly dropped after moved inside alternation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.