Reputation: 49
I have these line options:
<40m:22s - ok
<40m:22m; - not ok
<40h:22s;<40m:22m - ok
<40m:22m;<40m:22m; - not ok
I need to check for semicolons. If I have one entry, then it shouldn't be. If I have several entries in a row, then the last entry should not have a semicolon.
Now I have so far only succeeded:
([<>][1-9][0-9][hms]:[1-9][0-9][hms][;?]+)(?<!;)
I will be grateful for any help, hint
Upvotes: 2
Views: 284
Reputation: 214949
The general pattern for a delimited list is
^ item (delimiter item)* $
To avoid self-repetition and make it all more or less readable, it would make sense to use variables, template strings and whitespace. This way your regexp looks like a grammar definition (what it actually is) and not as a soup of symbols.
let term = `[1-9] [0-9] [hms]`
let item = `< ${term} : ${term}`
let list = `^ ${item} ( ; ${item} )* $`
let re = new RegExp(list.replace(/\s/g, ''))
console.log(re)
test = `
<40m:22s
<40m:22m;
<40h:22s;<40m:22m
<40m:22m;<40m:22m;
`
for (t of test.trim().split('\n'))
console.log(t, re.test(t))
Upvotes: 2
Reputation: 626690
You can use
^(?:[<>][1-9][0-9]?[hms]:[1-9][0-9]?[hms](?:;(?!$)|$))+$
Or, a bit more verbose since it includes a repetition of the main pattern:
^[<>][1-9][0-9]?[hms]:[1-9][0-9]?[hms](?:;[<>][1-9][0-9]?[hms]:[1-9][0-9]?[hms])*$
See the regex #1 demo and regex #2 demo.
Details:
^
- start of string(?:[<>][1-9][0-9]?[hms]:[1-9][0-9]?[hms](?:;(?!$)|$))+
- one or more repetitions of
[<>]
- a <
or >
char[1-9]
- a non-zero digit[0-9]?
- an optional digit (remove ?
if it must be obligatory) -
h,
mor
s`:
- a colon[1-9][0-9]?[hms]
- a non-zero digit, an optional digit and h
/m
/s
(?:;(?!$)|$)
- a ;
not at the end of string or end of string$
- end of string.The ^[<>][1-9][0-9]?[hms]:[1-9][0-9]?[hms](?:;[<>][1-9][0-9]?[hms]:[1-9][0-9]?[hms])*$
pattern follows the ^<MAIN>(?:<SEP><MAIN>)*$
scheme, and this pattern can be easily built dynamically using RegExp
constructor.
const texts = ['<40m:22s', '<40m:22m;', '<40h:22s;<40m:22m', '<40m:22m;<40m:22m;'];
const rx = /^(?:[<>][1-9][0-9]?[hms]:[1-9][0-9]?[hms](?:;(?!$)|$))+$/;
for (let text of texts) {
console.log(text, '=>', rx.test(text));
}
Upvotes: 2
Reputation: 576
Lets simplify the problem to a = [<>][1-9][0-9][hms]:[1-9][0-9][hms]
, so the accepted strings can be
a - ok
a;a - ok
a; - not ok
a;a; - not ok
so our regex must end with a
which leads to a$
now we want to accept none or multiple a
with ;
between each a
, the regex for that is (a;)*
combining these 2 will resut in const regex = /^(a;)*a$/;
now if we replace a
with [<>][1-9][0-9][hms]:[1-9][0-9][hms]
the result will be const regex = /^([<>][1-9][0-9][hms]:[1-9][0-9][hms];)*[<>][1-9][0-9][hms]:[1-9][0-9][hms]$/;
Upvotes: 0