As you have tagged your question with both C# and Java, I’m not going to give you a code solution here, but the basic idea.
If you split the string by ,
, you get a list of substrings: "1", "3" , "4", "5", "8", "10", "12", "14", "19", "14"
. Now, you could just loop over those and try to parse each as an integer. If it fails, it was not a number. And if it succeeds, you can easily check if it is < 0
or > 20
. And you can also keep a set of numbers you already had before and check if the current one was repeated.
The bottom line is, that you shouldn’t try to use regular expressions for everything. And your language requirement is not regular anyway (if you need to remember stuff, or count things, it is usually not regular). Perl based RegExps are capable of a bit more than just regular but it is not enough here.
Solution as regular expression
As you said in the comments, one line is limited to hold at most 20 numbers. As each number is also limited to be between zero and twenty, you have a finite amount of possibilities for how the line can actually look. As such, you have a finite language (with a finite number of possible lines). Finite languages are a subset of regular languages and as such, you can “easily” represent the language with regular expressions.
The simplest solution would be to just list every possible line. So, if you had just 3 numbers per line with 5 being the highest number (just to keep things simple), the regular expression could look like this:
0,1,2|0,1,3|0,1,4|0,1,5|0,2,3|0,2,4|0,2,5|0,3,4|0,3,5|0,4,5|1,2,3|1,2,4|1,2,5|1,3,4|1,3,5|1,4,5|2,3,4
Of course, you could simplify that a lot then (maybe even more):
0,(1,(2|3|4|5)|2,(3|4|5)|3,(4|5)|4,5)|1,(2,(3|4|5)|3,(4|5)|4,5)|2,(3,(4|5)|4,5)|3,4,5
But yeah, if you have a requirements that make a language finite, it also gets regular, but not necessarily pretty; and I would argue that the “manual” solution is still a lot more readable and especially more flexible.