Karen
Karen

Reputation: 49

How can I check the last character in a string?

I have these line options:

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

Answers (3)

georg
georg

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

Wiktor Stribiżew
Wiktor Stribiżew

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)
    • [hms] -h, mors`
    • : - 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

Hamza Jadid
Hamza Jadid

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]$/;

demo

Upvotes: 0

Related Questions