0

i have been trying with this for a while and failing, not that good with regex, what i need is the following:

A user name (the name of the person not a username)

it can include - because some names have hyphen in them (max of 2 allowed)

it can include a space (up to 3)

it cannot include numbers and must start with a letter not a hyphen

it must be at least 3 chars and 30 max

it must accommodate to people with non English letters (e.g. Agnès)

I tried this but it failed, it allowed starting with a number and did not accept non English letters like è or ï

^[a-zA-Z\-]{3,30}$

Any help would be highly appreciated and I think this will help many programmers searching SO

4
  • Don't use [a-zA-Z-] but \D (or the equivalent [^0-9]) Commented Feb 6, 2017 at 20:09
  • 1
    This is a task better not solved with regex anyway. Commented Feb 6, 2017 at 20:09
  • You either need to use XRegExp or build a custom Unicode letter class. Commented Feb 6, 2017 at 21:45
  • With XRegExp you can build a pattern like ^(?!(?:[^ ]* ){4})(?!(?:[^-]*-){3})\p{L}[\p{L} -]{2,29}$. Commented Feb 6, 2017 at 22:18

1 Answer 1

1

I think this might be the answer:

/** Check if name is valid.
 * @param {String} name
 * @returns {Boolean}
 */
const validateName = (name) => {
    name = name.trim().replace(/\s+/, ' ')
    if (name.length > 30 || name.length < 3) return false // length is too long or too short
    if ((name.match(/-/g) || []).length > 2) return false // more than 2 '-' found
    if ((name.match(/\s+/g) || []).length > 3) return false // more than 3 'whitespace chains' found
    if (name.match(/[~`!@#$%^&*()_=+\d[\]{}\\|:;"'<>,.\/?]/)) return false // not alowed char found
    name = name.split(/\s+/g)
    for (let part of name)
        if (part[0] === '-') return false // part of name starts with -

    return true
}

console.log(`Agnès Jaszenko: ${validateName("Agnès Jaszenko")}`) // valid
console.log(`Ag: ${validateName("Ag")}`) // too short
console.log(`Aga-ta roko-la-foo: ${validateName("Aga-ta roko-la-foo")}`) // too many -
console.log(`Agata Jolanta Krzyżtofska-Brzęczyszczewiczykówna: ${validateName("Agata Jolanta Krzyżtofska-Brzęczyszczewiczykówna")}`) // to long
console.log(`   Pan     Janusz   Kocioł  : ${validateName("   Pan     Janusz   Kocioł  ")}`) // valid
console.log(`Maciej Kozieja: ${validateName("Maciej Kozieja")}`) // fancy :3 hah :P - valid
console.log(`-Łarjusz Miętocha: ${validateName("-Łarjusz Miętocha")}`) // starting with -
console.log(`Łarjusz@ Miętocha: ${validateName("Łarjusz@ Miętocha")}`) // not alowed char
console.log(`محمد: ${validateName("محمد")}`) // valid with arabic symbols
console.log(`مح1مد: ${validateName("مح1مد")}`) // not valid char found

You can modify this code and return information to user about what is invalid or just use it like this.
Hope it works for you :D

How it works?

step 1 .trim() removes all whitespace at begining and end.
step 2 .replace(/\s+/, ' ') replace all whitespace left with exacly one space (doing this allows for 'Name Name' to be valid and 'reduces length' - actual count of words)
step 3 name.length > 30 || name.length < 3 checking the length
step 4 name.match(/-/g) counting '-'
sadly while thers no count matches and simple name.match(/-/g).length would break when no match was found thats why we have to use this 'trick' with 'default value'
step 5 name.match(/\s+/g) counting whitespaces
step 6 name.match(/[~`!@#$%^&*()_=+\d[\]{}\\|:;"'<>,.\/?]/) checking if name contains any of not alowed chars
Sadly as you know \d is not enough to check for all languages but you can reverse this proces and check if name contains any of not allowed chars
step 7 check if part of word begins with -
step 8 if all tests passed your name is valid and true is returned :)

Live Preview:

/** Check if name is valid.
 * @param {String} name
 * @returns {Boolean}
 */
const validateName = (name) => {
    name = name.trim().replace(/\s+/g, ' ')
    if (name.length > 30 || name.length < 3) return false // length is too long or too short
    if ((name.match(/-/g) || []).length > 2) return false // more than 2 '-' found
    if ((name.match(/\s+/g) || []).length > 3) return false // more than 3 'whitespace chains' found
    if (name.match(/[~`!@#$%^&*()_=+\d[\]{}\\|:;"'<>,.\/?]/)) return false // not alowed char found
    name = name.split(/\s+/g)
    for (let part of name)
        if (part[0] === '-') return false // part of name starts with -

    return true
}

const input = document.createElement('input')
const valid = document.createElement('p')
input.addEventListener('keyup', () =>{
  valid.innerHTML = validateName(input.value)
})
document.body.append(input)
document.body.append(valid)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.