ren
ren

Reputation: 55

regex - don't allow name to finish with hyphen

I'm trying to create a regex using javascript that will allow names like abc-def but will not allow abc- (hyphen is also the only nonalpha character allowed)

The name has to be a minimum of 2 characters. I started with ^[a-zA-Z-]{2,}$, but it's not good enough so I'm trying something like this ^([A-Za-z]{2,})+(-[A-Za-z]+)*$.

It can have more than one - in a name but it should never start or finish with -.

It's allowing names like xx-x but not names like x-x. I'd like to achieve that x-x is also accepted but not x-.

Thanks!

Upvotes: 4

Views: 5164

Answers (7)

Mohammed Elhag
Mohammed Elhag

Reputation: 4302

Use this if you want to accept such as A---A as well :

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

https://regex101.com/r/4UYd9l/4/

If you don't want to accept such as A---A do this:

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

https://regex101.com/r/qH4Q0q/4/

So both will accept only word starting from two characters of the pattern [A-Za-z-] and not start or end (?!-|.*-$) (negative lookahead) with - .

Upvotes: 1

muecas
muecas

Reputation: 4335

The problem is that the first assertion accepts 2 or more [A-Za-z]. You will need to modify it to accept one or more character:

^[A-Za-z]+((-[A-Za-z]{1,})+)?$

Edit: solved some commented issues

/^[A-Za-z]+((-[A-Za-z]{1,})+)?$/.test('xggg-dfe'); // Logs true
/^[A-Za-z]+((-[A-Za-z]{1,})+)?$/.test('x-d'); // Logs true
/^[A-Za-z]+((-[A-Za-z]{1,})+)?$/.test('xggg-'); // Logs false

Edit 2: Edited to accept characters only

/^[A-Za-z]+((-[A-Za-z]{1,})+)?$/.test('abc'); // Logs true

Upvotes: 1

Regular Jo
Regular Jo

Reputation: 5510

^(?=[A-Za-z](?:-|[A-Za-z]))(?:(?:-|^)[A-Za-z]+)+$

Asserts that

  • the first character is a-z
  • the second is a-z or hyphen

If this matches

  • looks for groups of one or more letters prefixed by a hyphen or start of string, all the way to end of string.

You can also use the I switch to make it case insensitive.

Upvotes: 0

KevBot
KevBot

Reputation: 18888

You can use a negative lookahead:

/(?!.*-$)^[a-z][a-z-]+$/i

Regex101 Example

Breakdown:

// Negative lookahead so that it can't end with a -
(?!.*-$)

// The actual string must begin with a letter a-z
[a-z]

// Any following strings can be a-z or -, there must be at least 1 of these
[a-z-]+

let regex = /(?!.*-$)^[a-z][a-z-]+$/i;

let test = [
  'xx-x',
  'x-x',
  'x-x-x',
  'x-',
  'x-x-x-',
  '-x',
  'x'
];

test.forEach(string => {
  console.log(string, ':', regex.test(string));
});

Upvotes: 3

ctwheels
ctwheels

Reputation: 22817

Option 1

This option matches strings that begin and end with a letter and ensures two - are not consecutive so a string like a--a is invalid. To allow this case, see the Option 2.

^[a-z]+(?:-?[a-z]+)+$
  • ^ Assert position at the start of the line
  • [a-z]+ Match any lowercase ASCII letter one or more times (with i flag this also matches uppercase variants)
  • (?:-?[a-z]+)+ Match the following one or more times
    • -? Optionally match -
    • [a-z]+ Match any ASCII letter (with i flag)
  • $ Assert position at the end of the line

var a = [
  "aa","a-a","a-a-a","aa-aa-aa","aa-a", // valid
  "aa-a-","a","a-","-a","a--a" // invalid
]
var r = /^[a-z]+(?:-?[a-z]+)+$/i

a.forEach(function(s) {
  console.log(`${s}: ${r.test(s)}`)
})


Option 2

If you want to match strings like a--a then you can instead use the following regex:

^[a-z]+[a-z-]*[a-z]+$

var a = [
  "aa","a-a","a-a-a","aa-aa-aa","aa-a","a--a", // valid
  "aa-a-","a","a-","-a" // invalid
]
var r = /^[a-z]+[a-z-]*[a-z]+$/i

a.forEach(function(s) {
  console.log(`${s}: ${r.test(s)}`)
})

Upvotes: 6

Aaron
Aaron

Reputation: 24812

I suggest the following :

^[a-zA-Z][a-zA-Z-]*[a-zA-Z]$

It validates :

  • that the matched string is at least composed of two characters (the first and last character classes are matched exactly once)
  • that the first and the last characters aren't dashes (the first and last character classes do not include -)
  • that the string can contain dashes and be greater than 2 characters (the second character class includes dashes and will consume as much characters as needed, dashes included).

Try it online.

Upvotes: 0

Ash
Ash

Reputation: 473

Try this /([a-zA-Z]{1,}-[a-zA-Z]{1,})/g

Upvotes: 0

Related Questions