Hellnar
Hellnar

Reputation: 64793

Regular expression for first and last name

For website validation purposes, I need first name and last name validation.

For the first name, it should only contain letters, can be several words with spaces, and has a minimum of three characters, but a maximum at top 30 characters. An empty string shouldn't be validated (e.g. Jason, jason, jason smith, jason smith, JASON, Jason smith, jason Smith, and jason SMITH).

For the last name, it should be a single word, only letters, with at least three characters, but at most 30 characters. Empty strings shouldn't be validated (e.g. lazslo, Lazslo, and LAZSLO).

Upvotes: 211

Views: 652318

Answers (19)

ProPhoto
ProPhoto

Reputation: 31

Here is my solution and let's compare all the top solutions here

/^(?=([A-ZÀ-ÝŐŰẞŒ]|([a-zß-ÿőűœ][ '])))(?=(?![a-zß-ÿőűœ]+[A-ZÀ-ÝŐŰẞŒ]))(?=(?!.[A-ZÀ-ÝŐŰẞŒ][A-ZÀ-ÝŐŰẞŒ]))(?=(?!.[- '][- ']))[A-ZÀ-ÝŐŰẞŒß-ÿőűœa-z- ']{2,}([a-zß-ÿőűœ]|(, Jr.))$/

Name This Sol-n maček CristianGuerrero Francois Muller John Boga Steve Kinzey
this is NOT a good regex expression fail passed passed fail passed fail
fail passed passed fail passed fail
''''''''''''''''''' fail passed passed fail passed fail
------------------- fail passed passed fail passed fail
*************** fail fail fail fail fail fail
###### ####### fail fail fail fail fail fail
!!! !!! !!! fail fail fail fail fail fail
[email protected] fail fail fail fail fail fail
s-Teve Smith fail passed passed fail passed passed Teve..
sTeve sMith fail passed passed passed passed fail
STEVE SMITH fail passed passed passed passed fail
Stev3 Smith fail fail fail fail fail fail
STeve Smith fail passed passed passed passed fail
Steve SMith fail passed passed passed passed fail
Steve Sm1th fail fail fail fail fail passed Steve Sm
John (extra space) Smith fail passed passed fail passed fail
'John Smith fail passed passed fail fail passed
John Smith- fail passed passed passed w.o. - passed passed
Ti O D fail passed passed fail passed fail
d'Are to Beaware passed passed passed fail passed passed
Jo Blow passed passed passed passed passed passed
Hyoung Kyoung Wu passed passed passed passed passed fail
Mike O'Neal passed passed passed passed passed passed w.o. O
Steve Johnson-Smith passed passed passed passed passed passed
Jozef-Schmozev Hiemdel passed passed passed fail passed passed
O Henry Smith passed passed passed fail passed passed w.o. O
Mathais d'Arras passed passed passed passed passed passed
Martin Luther King Jr passed passed passed passed passed passed
Downtown-James Brown passed passed passed fail passed passed
Darren McCarty passed passed passed passed passed passed
An Ni passed passed passed fail passed passed
George De FunkMaster passed passed passed fail passed passed
Kurtis B-Ball Basketball passed passed passed passed passed 50%
Ahmad el Jeffe passed passed passed fail passed passed
André Désirée Jördis passed passed passed fail passed fail
René Jürg passed passed passed fail passed fail
Esmé Adélaïde passed passed passed fail passed fail
Adorján Ágnes passed passed passed fail passed fail
Bendegúz Bertók passed passed passed fail passed fail
Ávg É Ñu passed passed passed fail passed fail
Ógl Ú Üd passed passed passed fail passed fail
Aarón Abrahán Aída passed passed passed fail passed fail
Íñigo Jerónima passed passed passed fail passed fail
Martin Luther King, Jr. passed passed passed passed w.o.,Jr. passed passed w.o.,Jr.

function myFunction() {
    
  const pattern = "^(?=([A-ZÀ-ÝŐŰẞŒ]|([a-zß-ÿőűœ][ '])))(?=(?![a-zß-ÿőűœ]+[A-ZÀ-ÝŐŰẞŒ]))(?=(?!.*[A-ZÀ-ÝŐŰẞŒ][A-ZÀ-ÝŐŰẞŒ]))(?=(?!.*[- '][- ']))[A-ZÀ-ÝŐŰẞŒß-ÿőűœa-z- ']{2,}([a-zß-ÿőűœ]|(, Jr.))$";
    var regex = new RegExp(pattern, 'gm');
    var a = document.getElementById("myText");
  var b = a.value;
  var c = regex.test(b);
  var d = document.getElementById("result") ;
  d.innerHTML = "Result:";
  if(b != ""){
      if(c){
          d.innerHTML += " passed";
      }
      else{
        d.innerHTML += " failed";
        }
  }
  else{
    return
  }
}
input[type=text] {
  width: 99%;
  padding: 4px;
  margin: 8px 0;
  display: inline-block;
  border: 1px solid #ccc;
  box-sizing: border-box;
}
button {
  background-color: #04AA6D;
  color: white;
  padding: 4px;
  border: none;
  cursor: pointer;
  width: 25%;
}

button:hover {
  opacity: 0.8;
}
<h2>Name Validation Regex Pattern </h2>
<div class="container">
      <label for="name"><b>Name</b></label>
        <input type="text" id="myText"  placeholder="Enter Your Name" name="name" value="">
</div>
 <div class="container">

<button onclick="myFunction()">Try it</button>
<p id="result"> Result: </p>
</div>
</div>

Upvotes: 0

maček
maček

Reputation: 77778

Don't forget about names like:

  • Mathias d'Arras
  • Martin Luther King, Jr.
  • Hector Sausage-Hausen

This should do the trick for most things:

/^[a-z ,.'-]+$/i

OR Support international names with super sweet unicode:

/^[a-zA-ZàáâäãåąčćęèéêëėįìíîïłńòóôöõøùúûüųūÿýżźñçčšžæÀÁÂÄÃÅĄĆČĖĘÈÉÊËÌÍÎÏĮŁŃÒÓÔÖÕØÙÚÛÜŲŪŸÝŻŹÑßÇŒÆČŠŽ∂ð ,.'-]+$/u

Upvotes: 307

Rez.Net
Rez.Net

Reputation: 1462

There is one issue with the top voted answer here which recommends this regex:

/^[a-z ,.'-]+$/i

It takes spaces only as a valid name!

The best solution in my opinion is to add a negative look forward to the beginning:

/^(?!\s)([a-z ,.'-]+)$/i

Upvotes: 6

Amir.n3t
Amir.n3t

Reputation: 3439

I didn't find any answer helpful for me simply because users can pick a non-english name and simple regex are not helpful. In fact it's actually very hard to find the right expression that works for all languages.

Instead, I picked a different approach and negated all characters that should not be in the name for the valid match. Below pattern negates numerical, special characters, control characters and '\', '/'

Final regex without punctuations: ["] ['] [,] [.], etc. :

^([^\p{N}\p{S}\p{C}\p{P}]{2,20})$

with punctuations:

^([^\p{N}\p{S}\p{C}\\\/]{2,20})$

With this, all these names are valid:

alex junior
沐宸
Nick
Sarah's Jane ---> with punctuation support
ביממה
حقیقت
Виктория

And following names become invalid:

🤣 Maria
k
١١١١١
123John

This means all names that don't have numerical characters, emojis, \ and are between 2-20 characters are allowed. You can edit the above regex if you want to add more characters to exclusion list.

To get more information about available patterns to include / exclude checkout this: https://www.regular-expressions.info/unicode.html#prop

Upvotes: 9

Aman Godara
Aman Godara

Reputation: 511

Read almost all highly voted posts (only some are good). After understanding the problem in detail & doing research, here are the tight regexes:

1). ^[A-Z][a-z]*(([,.] |[ '-])[A-Za-z][a-z]*)*(\.?)$

  • name Z is allowed contrary to the assumption made by some in the thread.
  • No leading or trailing spaces are allowed, empty string is NOT allowed, string containing only spaces is NOT allowed
  • Supports English alphabets only
  • Supports hyphens (Some-Foobarbaz-name, Some foobarbaz-Name), apostrophes (David D'Costa, David D'costa, David D'costa R'Costa p'costa), periods (Dr. L. John, Robert Downey Jr., Md. K. P. Asif) and commas (Martin Luther, Jr.).
  • First alphabet of only the first word of a name MUST be capital.
    NOT Allowed: John sTeWaRT, JOHN STEWART, Md. KP Asif, John Stewart PhD
    Allowed: John Stewart, John stewart, Md. K P Asif
    you can easily modify this condition.

If you also want to allow names like Queen Elizabeth 2 or Henry IV:
2). ^[A-Z][a-z]*(([,.] |[ '-])[A-Za-z][a-z]*)*([.]?| (-----)| [1-9][0-9]*)$

replace ----- with roman numeral's regex (which itself is long) OR you can use this alternative regex which is based on KISS philosophy [IVXLCDM]+ (here I, V, X, ... in ANY random order will satisfy the regex).


I personally suggest to use this regex:
3). ^[A-Z][a-z]*(([,.] |[ '-])[A-Za-z][a-z]*)*(\.?)( [IVXLCDM]+)?$
Feel free to try this regex HERE & make any modifications of your choice.

I have provided with tight regex which covers every possible name I found on my research with no bug. Modify these regexes to relax some of the unwanted constraints.


[UPDATE - March, 2022]

Here are 4 more regexes:

^[A-Za-z]+(([,.] |[ '-])[A-Za-z]+)*([.,'-]?)$

^((([,.'-]| )(?<!( {2}|[,.'-]{2})))*[A-Za-z]+)+[,.'-]?$

^( ([A-Za-z,.'-]+|$))+|([A-Za-z,.'-]+( |$))+$

^(([ ,.'-](?<!( {2}|[,.'-]{2})))*[A-Za-z])+[ ,.'-]?$

It's been a while since I looked back at these 4 regexes so I forgot their specifications. These 4 regexes are not tight, unlike the previous ones but do the job very well. These regexes distinguish 3 parts of a name: English alphabet, space and special character. Which one you need out of these 4 depends on your answer (Yes/No) to these questions:

  1. have at least 1 alphabet?
  2. can start with a space or a special character?
  3. can end with a space or a special character?
  4. are 2 consecutive spaces allowed?
  5. are 2 consecutive special characters allowed?

Note: name validation should ONLY serve as a warning NOT a necessity a name should fulfill because there is no fixed naming pattern, if there is one it can change overnight and thus, any tight regex you come across will become obsolete somewhere in future.

Upvotes: 7

pablorsk
pablorsk

Reputation: 4286

If you are searching a simplest way, just check almost 2 words.

/^[^\s]+( [^\s]+)+$/

Valid names

  • John Doe
  • pedro alberto ch
  • Ar. Gen
  • Mathias d'Arras
  • Martin Luther King, Jr.

No valid names

  • John
  • 陳大文

Upvotes: 1

John Boga
John Boga

Reputation: 532

I've tried almost everything on this page, then I decided to modify the most voted answer which ended up working best. Simply matches all languages and includes .,-' characters.

Here it is:

/^[\p{L} ,.'-]+$/u

Upvotes: 21

Francois Muller
Francois Muller

Reputation: 566

I have created a custom regex to deal with names:

I have tried these types of names and found working perfect

  1. John Smith
  2. John D'Largy
  3. John Doe-Smith
  4. John Doe Smith
  5. Hector Sausage-Hausen
  6. Mathias d'Arras
  7. Martin Luther King
  8. Ai Wong
  9. Chao Chang
  10. Alzbeta Bara

My RegEx looks like this:

^([a-zA-Z]{2,}\s[a-zA-Z]{1,}'?-?[a-zA-Z]{2,}\s?([a-zA-Z]{1,})?)

MVC4 Model:

[RegularExpression("^([a-zA-Z]{2,}\\s[a-zA-Z]{1,}'?-?[a-zA-Z]{2,}\\s?([a-zA-Z]{1,})?)", ErrorMessage = "Valid Charactors include (A-Z) (a-z) (' space -)") ]

Please note the double \\ for escape characters

For those of you that are new to RegEx I thought I'd include a explanation.

^               // start of line
[a-zA-Z]{2,}    // will except a name with at least two characters
\s              // will look for white space between name and surname
[a-zA-Z]{1,}    // needs at least 1 Character
\'?-?           // possibility of **'** or **-** for double barreled and hyphenated surnames
[a-zA-Z]{2,}    // will except a name with at least two characters
\s?             // possibility of another whitespace
([a-zA-Z]{1,})? // possibility of a second surname

Upvotes: 46

Snowbases
Snowbases

Reputation: 2401

This regex work for me (was using in Angular 8) :

([a-zA-Z',.-]+( [a-zA-Z',.-]+)*){2,30}

enter image description here

It will be invalid if there is:-

  1. Any whitespace start or end of the name
  2. Got symbols e.g. @
  3. Less than 2 or more than 30

Example invalid First Name (whitespace)

enter image description here

Example valid First Name :

enter image description here

Upvotes: 8

Mihail Fernandes
Mihail Fernandes

Reputation: 31

^\p{L}{2,}$

^ asserts position at start of a line.

\p{L} matches any kind of letter from any language

{2,} Quantifier — Matches between 2 and unlimited times, as many times as possible, giving back as needed (greedy)

$ asserts position at the end of a line

So it should be a name in any language containing at least 2 letters(or symbols) without numbers or other characters.

Upvotes: 3

J Dorrian
J Dorrian

Reputation: 204

For first and last names theres are really only 2 things you should be looking for:

  1. Length
  2. Content

Here is my regular expression:

var regex = /^[A-Za-z-,]{3,20}?=.*\d)/

1. Length

Here the {3,20} constrains the length of the string to be between 3 and 20 characters.

2. Content

The information between the square brackets [A-Za-z] allows uppercase and lowercase characters. All subsequent symbols (-,.) are also allowed.

Upvotes: -1

Alexander Burakevych
Alexander Burakevych

Reputation: 2426

I'm working on the app that validates International Passports (ICAO). We support only english characters. While most foreign national characters can be represented by a character in the Latin alphabet e.g. è by e, there are several national characters that require an extra letter to represent them such as the German umlaut which requires an ‘e’ to be added to the letter e.g. ä by ae.

This is the JavaScript Regex for the first and last names we use:

/^[a-zA-Z '.-]*$/

The max number of characters on the international passport is up to 31. We use maxlength="31" to better word error messages instead of including it in the regex.

Here is a snippet from our code in AngularJS 1.6 with form and error handling:

class PassportController {
  constructor() {
    this.details = {};
    // English letters, spaces and the following symbols ' - . are allowed
    // Max length determined by ng-maxlength for better error messaging
    this.nameRegex = /^[a-zA-Z '.-]*$/;
  }
}

angular.module('akyc', ['ngMessages'])
  .controller('PassportController', PassportController);
 
.has-error p[ng-message] {
  color: #bc111e;
}

.tip {
  color: #535f67;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<script src="https://code.angularjs.org/1.6.6/angular-messages.min.js"></script>

<main ng-app="akyc" ng-controller="PassportController as $ctrl">
  <form name="$ctrl.form">

    <div name="lastName" ng-class="{ 'has-error': $ctrl.form.lastName.$invalid} ">
        <label for="pp-last-name">Surname</label>
        <div class="tip">Exactly as it appears on your passport</div>
        <div ng-messages="$ctrl.form.lastName.$error" ng-if="$ctrl.form.$submitted" id="last-name-error">
          <p ng-message="required">Please enter your last name</p>
          <p ng-message="maxlength">This field can be at most 31 characters long</p>
          <p ng-message="pattern">Only English letters, spaces and the following symbols ' - . are allowed</p>
        </div>
        
        <input type="text" id="pp-last-name" ng-model="$ctrl.details.lastName" name="lastName"
               class="form-control" required ng-pattern="$ctrl.nameRegex" ng-maxlength="31" aria-describedby="last-name-error" />
      </div>

      <button type="submit" class="btn btn-primary">Test</button>

  </form>
</main>

Upvotes: 8

CristianGuerrero
CristianGuerrero

Reputation: 1293

After going through all of these answers I found a way to build a tiny regex that supports most languages and only allows for word characters. It even supports some special characters like hyphens, spaces and apostrophes. I've tested in python and it supports the characters below:

^[\w'\-,.][^0-9_!¡?÷?¿/\\+=@#$%ˆ&*(){}|~<>;:[\]]{2,}$

Characters supported:

abcdefghijklmnopqrstwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
áéíóúäëïöüÄ'
陳大文
łŁőŐűŰZàáâäãåąčćęèéêëėįìíîïłńòóôöõøùúûüųū
ÿýżźñçčšžÀÁÂÄÃÅĄĆČĖĘÈÉÊËÌÍÎÏĮŁ
ŃÒÓÔÖÕØÙÚÛÜŲŪŸÝŻŹÑßÇŒÆČŠŽ.-
ñÑâê都道府県Федерации
আবাসযোগ্য জমির걸쳐 있는

Upvotes: 67

Asim K T
Asim K T

Reputation: 18144

As maček said:

Don't forget about names like:

Mathias d'Arras

Martin Luther King, Jr.

Hector Sausage-Hausen

and to remove cases like:

..Mathias

Martin king, Jr.-

This will cover more cases:

^([a-z]+[,.]?[ ]?|[a-z]+['-]?)+$

Upvotes: 8

M&#225;ťa - Stitod.cz
M&#225;ťa - Stitod.cz

Reputation: 893

So, with customer we create this crazy regex:

(^$)|(^([^\-!#\$%&\(\)\*,\./:;\?@\[\\\]_\{\|\}¨ˇ“”€\+<=>§°\d\s¤®™©]| )+$)

Upvotes: -1

malix
malix

Reputation: 3572

I use:

/^(?:[\u00c0-\u01ffa-zA-Z'-]){2,}(?:\s[\u00c0-\u01ffa-zA-Z'-]{2,})+$/i

And test for maxlength using some other means

Upvotes: 4

Steve Kinzey
Steve Kinzey

Reputation: 371

I have searched and searched and played and played with it and although it is not perfect it may help others making the attempt to validate first and last names that have been provided as one variable.

In my case, that variable is $name.

I used the following code for my PHP:

    if (preg_match('/\b([A-Z]{1}[a-z]{1,30}[- ]{0,1}|[A-Z]{1}[- \']{1}[A-Z]{0,1}  
    [a-z]{1,30}[- ]{0,1}|[a-z]{1,2}[ -\']{1}[A-Z]{1}[a-z]{1,30}){2,5}/', $name)  
    # there is no space line break between in the above "if statement", any that   
    # you notice or perceive are only there for formatting purposes.  
    # 
    # pass - successful match - do something
    } else {
    # fail - unsuccessful match - do something

I am learning RegEx myself but I do have the explanation for the code as provided by RegEx buddy.
Here it is:

Assert position at a word boundary «\b»

Match the regular expression below and capture its match into backreference number 1
«([A-Z]{1}[a-z]{1,30}[- ]{0,1}|[A-Z]{1}[- \']{1}[A-Z]{0,1}[a-z]{1,30}[- ]{0,1}|[a-z]{1,2}[ -\']{1}[A-Z]{1}[a-z]{1,30}){2,5}»

Between 2 and 5 times, as many times as possible, giving back as needed (greedy) «{2,5}»

* I NEED SOME HELP HERE WITH UNDERSTANDING THE RAMIFICATIONS OF THIS NOTE *

Note: I repeated the capturing group itself. The group will capture only the last iteration. Put a capturing group around the repeated group to capture all iterations. «{2,5}»

Match either the regular expression below (attempting the next alternative only if this one fails) «[A-Z]{1}[a-z]{1,30}[- ]{0,1}»

Match a single character in the range between “A” and “Z” «[A-Z]{1}»

Exactly 1 times «{1}»

Match a single character in the range between “a” and “z” «[a-z]{1,30}»

Between one and 30 times, as many times as possible, giving back as needed (greedy) «{1,30}»

Match a single character present in the list “- ” «[- ]{0,1}»

Between zero and one times, as many times as possible, giving back as needed (greedy) «{0,1}»

Or match regular expression number 2 below (attempting the next alternative only if this one fails) «[A-Z]{1}[- \']{1}[A-Z]{0,1}[a-z]{1,30}[- ]{0,1}»

Match a single character in the range between “A” and “Z” «[A-Z]{1}»

Exactly 1 times «{1}»

Match a single character present in the list below «[- \']{1}»

Exactly 1 times «{1}»

One of the characters “- ” «- » A ' character «\'»

Match a single character in the range between “A” and “Z” «[A-Z]{0,1}»

Between zero and one times, as many times as possible, giving back as needed (greedy) «{0,1}»

Match a single character in the range between “a” and “z” «[a-z]{1,30}»

Between one and 30 times, as many times as possible, giving back as needed (greedy) «{1,30}»

Match a single character present in the list “- ” «[- ]{0,1}»

Between zero and one times, as many times as possible, giving back as needed (greedy) «{0,1}»

Or match regular expression number 3 below (the entire group fails if this one fails to match) «[a-z]{1,2}[ -\']{1}[A-Z]{1}[a-z]{1,30}»

Match a single character in the range between “a” and “z” «[a-z]{1,2}»

Between one and 2 times, as many times as possible, giving back as needed (greedy) «{1,2}»

Match a single character in the range between “ ” and “'” «[ -\']{1}»

Exactly 1 times «{1}»

Match a single character in the range between “A” and “Z” «[A-Z]{1}»

Exactly 1 times «{1}»

Match a single character in the range between “a” and “z” «[a-z]{1,30}»

Between one and 30 times, as many times as possible, giving back as needed (greedy) «{1,30}»

I know this validation totally assumes that every person filling out the form has a western name and that may eliminates the vast majority of folks in the world. However, I feel like this is a step in the proper direction. Perhaps this regular expression is too basic for the gurus to address simplistically or maybe there is some other reason that I was unable to find the above code in my searches. I spent way too long trying to figure this bit out, you will probably notice just how foggy my mind is on all this if you look at my test names below.

I tested the code on the following names and the results are in parentheses to the right of each name.

  1. STEVE SMITH (fail)
  2. Stev3 Smith (fail)
  3. STeve Smith (fail)
  4. Steve SMith (fail)
  5. Steve Sm1th (passed on the Steve Sm)
  6. d'Are to Beaware (passed on the Are to Beaware)
  7. Jo Blow (passed)
  8. Hyoung Kyoung Wu (passed)
  9. Mike O'Neal (passed)
  10. Steve Johnson-Smith (passed)
  11. Jozef-Schmozev Hiemdel (passed)
  12. O Henry Smith (passed)
  13. Mathais d'Arras (passed)
  14. Martin Luther King Jr (passed)
  15. Downtown-James Brown (passed)
  16. Darren McCarty (passed)
  17. George De FunkMaster (passed)
  18. Kurtis B-Ball Basketball (passed)
  19. Ahmad el Jeffe (passed)

If you have basic names, there must be more than one up to five for the above code to work, that are similar to those that I used during testing, this code might be for you.

If you have any improvements, please let me know. I am just in the early stages (first few months of figuring out RegEx.

Thanks and good luck, Steve

Upvotes: 15

Sjoerd
Sjoerd

Reputation: 75598

You make false assumptions on the format of first and last name. It is probably better not to validate the name at all, apart from checking that it is empty.

Upvotes: 144

Jens
Jens

Reputation: 25563

First name would be

"([a-zA-Z]{3,30}\s*)+"

If you need the whole first name part to be shorter than 30 letters, you need to check that seperately, I think. The expression ".{3,30}" should do that.

Your last name requirements would translate into

"[a-zA-Z]{3,30}"

but you should check these. There are plenty of last names containing spaces.

Upvotes: 8

Related Questions