RegEx at most one single quote in the middle

Viewed 150

I've written a regular expression to accept alpha (a-z) case insensitive, single quote, or hyphen only.

/^[a-zA-Z'-]+$/

Matches: Marie-Poppins-O'Connor

How can i tweak this further to enforce the following additional rules

  1. hyphen and single-quote NOT at the beginning or end
  2. at most one single-quote
  3. hyphen and quote must not be adjacent to each other (letter must separate them)

Help !

NB: regex dialect is whatever works with JavaScript.

4 Answers

You could use a negative lookahead to assert that at most one single quote occurs:

/^(?!.*'.*')(?!.*(?:-'|'-))[A-Za-z](?:[a-zA-Z'-]*[A-Za-z])?$/

Sample script:

console.log(/^(?!.*'.*')(?!.*(?:-'|'-))[A-Za-z](?:[a-zA-Z'-]*[A-Za-z])?$/.test("Marie-Poppins-O'Connor"));
console.log(/^(?!.*'.*')(?!.*(?:-'|'-))[A-Za-z](?:[a-zA-Z'-]*[A-Za-z])?$/.test("O'Connor-O'Connor"));
console.log(/^(?!.*'.*')(?!.*(?:-'|'-))[A-Za-z](?:[a-zA-Z'-]*[A-Za-z])?$/.test("'Hello World"));
console.log(/^(?!.*'.*')(?!.*(?:-'|'-))[A-Za-z](?:[a-zA-Z'-]*[A-Za-z])?$/.test("Mary O-'Connor"));

const regx = /^(?!.*'.*')(?!.*(?:-'|'-|--|''))[a-zA-Z](?:[a-zA-Z'-]*)[A-Za-z]$/; 

My modified answer (thanks to Tim Biegeleisen's answer which i accepted), rewritten in a way that i can understand.

Essentially there are 3 groups

[a-zA-Z](?:[a-zA-Z'-]*)[A-Za-z]

The above says begin with a-z, optional part in the middle 0 or more times, and end with a-z. (Do i really need the ?: in the group, not sure, feel free to comment).

(?!.*(?:-'|'-|--|''))

The above says don't allow quote, hyphen, or hyphen-hyphen, or quote-quote to be adjacent

 (?!.*'.*')

And finally the above says don't allow occurence of quotes twice.

YAY! matches with "Mary-Poppins-Hot-Chick-O'Connor". Minimal pass "Ab"

Try this:

let regex = /^([A-Za-z]+([A-Za-z-]+)?)?[A-Za-z]'?[A-Za-z](([A-Za-z-]+)?[A-Za-z]+)?)?$/

console.log('aa', regex.test('aa'))
console.log('a-a', regex.test('a-a'))
console.log("a'a", regex.test("a'a"))
console.log("a-'aa", regex.test("a-'aa"))
console.log("a-a'a", regex.test("a-a'a"))
console.log("aaa", regex.test("aaa"))
console.log("a-a'a-a", regex.test("a-a'a-a"))
console.log("a-a'a-a'", regex.test("a-a'a-a'"))

You could use the following regular expression (with the case-indifferent flag set) to validate the string.

^(?!['-]|.*(?:'-|-'))[a-z-]*'?[a-z-]*[a-z]$

Demo

Javascript's regex engine performs the following operations.

^            :match beginning of string
(?!          :begin negative lookahead
  ['-]       :match "'-" or "-'" at beginning of string
  |          :or
  .*         :match 0+ characters
  (?:'-|-')  :match "'-" or "-'" in a non-capture group
)            :end negative lookahead
[a-z-]*      :match 0+ letters or hyphens 
'?           :optionally match single quote
[a-z-]*      :match 0+ letters or hyphens
[a-z]        :match a letter
$            :match end of string

Note that this matches a string consisting of a single letter but not an empty string.

Related