22
  1. How can I disallow -- (more than 1 consecutive -)? e.g. ab--c
  2. - at the back of words not allow, e.g. abc-
  3. - at start of words not allow, e.g. -abc

^[A-Za-z0-9-]+$ is what I have so far.

cometta
  • 35,071
  • 77
  • 215
  • 324

5 Answers5

42
^(?!-)(?!.*--)[A-Za-z0-9-]+(?<!-)$

Explanation:

^             # Anchor at start of string
(?!-)         # Assert that the first character isn't a -
(?!.*--)      # Assert that there are no -- present anywhere
[A-Za-z0-9-]+ # Match one or more allowed characters
(?<!-)        # Assert that the last one isn't a -
$             # Anchor at end of string
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • Sorry, this also does not match abd- – Sachin Shanbhag Feb 04 '11 at 11:25
  • @Sachin: As it shouldn't. The OP is listing three conditions he wants to disallow. (If he wanted to allow dashes at the start/end, why would he have mentioned them at all?) – Tim Pietzcker Feb 04 '11 at 11:27
  • Firefox 4 errors out on this one. `^[^-]+(?!.*--).+[^-]+$` does work. Tested with http://jsbin.com/ujoxu3 . – Martijn Feb 04 '11 at 11:44
  • @Martijn, unfortunately yours does not match if the total length is less than 3 characters. – Brian Reichle Feb 04 '11 at 12:12
  • @Brian: you’re right. I just can’t figure out why Firefox refuses Tim’s. – Martijn Feb 04 '11 at 12:25
  • @Martijn, apparently [javascript does not support negative lookbehind](http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript). – Brian Reichle Feb 04 '11 at 12:34
  • @Brian: yes, that’s it (thanks for the link, interesting article). One way of solving it is by separately checking for one and two-character strings: `^([^-]{0,2}|[^-]+(?!.*--).*[^-]+)$` (http://jsbin.com/ujoxu3/2 ) – Martijn Feb 04 '11 at 12:42
  • @Martijn, persionally I would prefer to avoid all these "lookarounds" as they tend to run slower. I don't see any room for a pathological case in Tim's answer but the negative lookahead/lookbehind are unnecessary all the same. – Brian Reichle Feb 04 '11 at 12:56
  • @Brian: I agree that it would be nicer without lookarounds. But I can’t see a way to avoid them _while keeping requirement 1 in mind_. If you try yours with http://jsbin.com/ujoxu3/3/, you’ll see that they fail. – Martijn Feb 04 '11 at 14:16
  • @Martijn: Mine, like Tim's answer and the starting point provided in the question, only allows alpha numeric characters and hyphen. if you want to any characters, then it can be simply modified as follows `^[^-]+(-[^-]+)*` – Brian Reichle Feb 04 '11 at 20:38
  • @Brian: I see — unfortunately, I had to go shortly after posting my answer (it was getting late), and now I can’t remove my downvote anymore. :-\ – Martijn Feb 07 '11 at 15:18
39

^[A-Za-z0-9]+(-[A-Za-z0-9]+)*$

Using this regular expression, the hyphen is only matched just inside the group. This hyphen has the [A-Za-z0-9]+ sub-expression appearing on each side. Because this sub-expression matches on one or more alpha numeric characters, its not possible for a hyphen to match at the start, end or next to another hyphen.

Brian Reichle
  • 2,798
  • 2
  • 30
  • 34
  • That's clever! Probably easier to understand than all my lookaround stuff. – Tim Pietzcker Feb 04 '11 at 11:21
  • 4
    @Sachin: As I understand the OP, that's exactly what he wants. He could be more explicit, though. – Tim Pietzcker Feb 04 '11 at 11:26
  • @Tim - Eeeesshhh... Totally misunderstood the question. @Brian - Absolutely this works. Thats why I was trying to match -abd and abd- in my regex... Thanks and sorry. – Sachin Shanbhag Feb 04 '11 at 11:27
  • @Brian: you seem to have overlooked the OP’s first requirements: that it disallow consecutive hyphens. – Martijn Feb 04 '11 at 14:15
  • @Martijn: No, it works fine. The hyphen is only ever matched just inside the group as a single hyphen character and must always be preceded and followed by at least one alphanumeric character. It only failed your test because you were testing with spaces and punctuation, which the question implied were not allowed (by the provded starting point). If you want to include those then use `^[^-]+(-[^-]+)*` – Brian Reichle Feb 04 '11 at 20:44
  • 2
    @Brian: you’re right. It is indeed more elegant (and faster) than lookaheads. +1 :-) – Martijn Feb 08 '11 at 07:31
2
^[a-zA-Z0-9](?!.*--)[a-zA-Z0-9-]*[a-zA-Z0-9]$

^[a-zA-Z0-9]     /*Starts with a letter or a number*/
(?!.*--)         /*Doesn't include 2 dashes in a row*/
[a-zA-Z0-9-]*    /*After first character, allow letters or numbers or dashes*/
[a-zA-Z0-9]$     /*Ends with a letter or a number*/

Matches:

Re-play / Re-play-ed

Doesn't Match:

Replay- / Re--Play / -Replay

Kareem
  • 5,068
  • 44
  • 38
2

Try: ^([a-zA-Z0-9]+[-]{1})*[a-zA-Z0-9]+$

Regex101 link: https://regex101.com/r/xZ2g6p/1

This allows only one hyphen inbetween two set of characters and blocks it at the beginning & at the end of the character set.

Ubanantu
  • 21
  • 2
1

If “-” is not allowed at the beginning nor end of the string, you are searching for a sequence of “one or more alanum, followed by one or more group(s) of one dash followed by 1 or more alanum”

/[0-9A-Z]+(-[0-9A-Z]+)+/

Simple is a valuable motto with regular expressions. (nota : to search small case characters, add them. I didn't for clarity)