linkyndy
linkyndy

Reputation: 17900

CSS numeric expression parser and validator

I need for my current project to parse and validate numeric expressions, similar to those used in CSS3's :nth-child(). Basically, the expression is an+b, where a and b must be integer values (both positive and negative). They can also be equal to 0.

Some examples to make everything more clear: 2n+1, 2n, 4 and n+2 should be valid. Basically, a and b are any kind of integers, signed or unsigned.

The following examples:

are all valid. This should fail only when a or b is not an integer, or if some other character is present in the expression.

I would like to know how can I parse and validate these expressions; I believe a suitable solution would be REGEXes, but I have no idea how can I build one for this.

Upvotes: 0

Views: 158

Answers (2)

Code Jockey
Code Jockey

Reputation: 6721

EDIT: revised to allow negative numbers as specified in the question END EDIT

If these are valid values:

5n+12   3456    -5     2     123n+6  8n    13n-6    n+2

And these are invalid:

25n.1   4x+4    2n+    6N-2  8n-+5   n+-3  Rn+T     x+1

then this expression should validate:

^(-?\d+(n([+-]\d+)?)?)$

This expression says:

^           # Assert beginning of line
(\d+        # Match one or more digits
  (n        #   TRY to Match a literal n character
    (\+\d+  #     TRY to match a literal plus character followed by one or more digits
    )?      #     END TRY
  )?        #   END TRY
)           # End Match
$           # Assert at end of string

The TRYs will attempt to validate, but will not mind if it is not there.

EDIT:

Though the above expression should validate, this expression should produce precisely the results you seek, using named capturing groups a and b, and a positive lookahead to capture only the numbers for a and b and to exclude the + symbol, but only capture the - symbol for negative numbers:

^(?:(?:(?P<a>-?\d*)n)?(?=[+-]?\d+|$)\+?(?P<b>-?\d+)?)$

Results should be as follows:

 source     a       b
------     ------  ------
 5n+12      5       12
 3456               3456
 2                  2
 123n+6     123     6
 8n         8           
 -5                 -5
 13n-6      13      -6
 n+2                2
 n

Because I am not completely sure how the <null value or nothing> vs ,zero length or null string> dichotomy works in PHP and preg_match_all, I would recommend using this expression if you encounter any problems differentiating between the results for n+2 and 2:

^(?:(?P<n>(?P<a>-?\d*)n)?(?=[+-]?\d+|$)\+?(?P<b>-?\d+)?)$

This captures the entire "n" expression or nothing if there is none, for n+2, 2, and 12n+2, this produces:

 source    n        a       b
------     ------  ------  ------
 2                          2
 n+2       n                2
 12n+2     12n      12      2

Upvotes: 3

SLaks
SLaks

Reputation: 887459

You want something like ^(?:(?:(-?\d*)n)?([+-]\d+)?|(\d+))$.
This will return the two numbers in the two successful capture groups.

Upvotes: 1

Related Questions