1

I've been trying to check if my string has an underscore or hyphen at either the beginning or the end.

// pass
sdq
lorem ipsum
abc_def
harry-_potter


// catch
fg_
_asq
_dqw-
-asq-sq

Tried out the following but I'm learning regex so I'm not quite sure how to go forward from here:

/^[-_]?.*[-_]$/

^        => beginning anchor
[-_]?    => start with either - or _, optionally
.*       => match any number of any character (I believe I could have used ranges here)
[-_]$    => check for - or _ at the end

I also know that one possible solution could be to use |, which is used for conditions, and what I need is to be able to check that:

There is either a hypher or underscore at the beginning or end of the string.

How can I check this? Can I use something other than |?

Sreetam Das
  • 3,226
  • 2
  • 22
  • 36

3 Answers3

2

Since OP has specifically asked this part:

Can I use something other than |?

Here is a regex solution that doesn't use alternation and uses negative lookahead to apply a condition that last character must not be _ or -:

/^(?!.*[-_]$)[^-_].*/mg

RegEx Details:

  • (?!.*[-_]$) is a negative lookahead that means fail the match is - or _ are found just before end of line.
  • [^-_] is a negated character class that means match any character that is not - or _.

RegEx Demo

Having said that most simple and efficient solution would be what I wrote in my comment earlier i.e. using alternation:

/^[-_]|[-_]$/mg

Use this regex to check and fail your mismatches.

anubhava
  • 761,203
  • 64
  • 569
  • 643
0

You'll need to alternate. Either match [-_] at the beginning (followed by other characters), or match any number of characters and then match [-_] at the end of the string:

^(?:[-_].*|.*[-_])$

https://regex101.com/r/e7ESHW/1

The group isn't necessary, but I think it makes the intent of the pattern clearer (a match must match the full length of the string). You can leave it out if you want:

^[-_].*|.*[-_]$

If you don't care at all about what characters get matched, and only want to see if the string starts with / ends with a dash or underscore, then you can leave out the .*s.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 6
    curious, why the group? and why the non-capturing? – dandavis Sep 18 '19 at 05:51
  • 1
    @dandavis Arguably, the group could be unnecessary but why you think it shouldn't be a non-capturing one? I'm also more curious why the downvote! I see nothing wrong with the answer. – 41686d6564 stands w. Palestine Sep 18 '19 at 05:53
  • @dandavis I was thinking that (like OP's current pattern) a match should span the whole length of the string, so `^` and `$` on either sides of an alternated group makes sure that occurs. Capturing groups should only be used when needed - if they're not needed, a non-capturing group should be used instead, it's both less expensive and makes the intent of the pattern clearer. – CertainPerformance Sep 18 '19 at 05:54
  • 2
    yeah, but you don't need a group at all in the first place – CinCout Sep 18 '19 at 05:55
  • @dandavis Not entirely sure how the pattern is being used, I was trying to fix OP's pattern while still matching the full strings. If OP is just using something like `.test`, then yeah, there's no need to check the other characters, but if he wants to extract certain matches, the whole length should be matched – CertainPerformance Sep 18 '19 at 06:06
0

Can I use something other than |?

Just in case you don't want to use regex, use startsWith and endsWith

let arr = ['sdq', 'lorem ipsum', 'abc_def', 'harry-_potter', 'fg_', '_asq', '_dqw-', '-asq-sq']

let tester = (str) => {
  return !(str.startsWith('-') || str.startsWith('_') || str.endsWith('-') || str.endsWith('_'))
}

arr.forEach(str => console.log(str, '--->', tester(str)))
Code Maniac
  • 37,143
  • 5
  • 39
  • 60