简体   繁体   中英

Can someone suggest a one-line regex to parse out alphanumeric and optional numeric ids with either a - or / separator?

I'm trying to parse a set of strings that follow the following patterns

{alpha-numeric-id}-{numeric-id}

or

{alpha-numeric-id}/{numeric-id}
  1. The alpha-numeric-id can include the - character, and numbers
  2. The numeric-id is always a number, and is optional.
  3. The alpha-numeric-id and the numeric-id may either be separated by a - or /

I want to parse out the alpha-numeric-id and numeric-id (if it's there) in a single step.

Examples

'ThePixies1996' => { 1: 'ThePixies1996', 2: '' }
'7ThePixies' => { 1: '7ThePixies', 2: '' }
'The-Pixies' => { 1: 'The-Pixies', 2: '' }
'The-Pixies-1234567' => { 1: 'The-Pixies', 2: '1234567' }
'The-Pixies/1234567' => { 1: 'The-Pixies', 2: '1234567' }

So far the simplest way I have come up with is as follows:

const parse = str => {
  const numeric = str.match(/[-\/]([0-9]+)/)

  return numeric
    ? {
      numericId: numeric[1],
      alphaNumericId: str.slice(0, -1 * (numeric[1].length + 1))
    }
    : {
      numericId: '',
      alphaNumericId: str
    }
}

Is there a simpler way?

A regular expression would be much more simpler if you know what you are going to do. Having said that, this would be a desirable solution:

^([\da-z-]+?)(?:[-/](\d+))?$

Explanation:

  • ^ Match beginning of string
  • ([\\da-z-]+?) Match and capture an alphanumeric string including - (non-greedy)
  • (?:[-/](\\d+))? Match a string starting with characters - or / that follows a sequence of digits (which is captured) optionally
  • $ End of string

See live demo

JS code:

 var matches = []; 'The-Pixies/12345'.replace(/^([\\da-z-]+?)(?:[-/](\\d+))?$/ig, function(m, $1, $2) { matches.push($1, $2); }) console.log(matches.filter(Boolean));

You can use

(.+?)(?:[\/-](\d+))?$

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

Capture the alphaNumericId in a group by lazy-repeating any characters, then optionally have a group of a dash or forward slash, followed by digits captured in another group, the numericId . Destructure the match and assign a default value (the empty string) to the numericId to return the desired object quickly:

 const input = ['ThePixies1996', '7ThePixies', 'The-Pixies', 'The-Pixies-1234567', 'The-Pixies/1234567' ]; function parse(str) { const [_, alphaNumericId, numericId = ''] = str.match(/(.+?)(?:[\\/-](\\d+))?$/); return { alphaNumericId, numericId }; } console.log( input.map(parse) );

That's assuming the inputs are always valid, like your parse function does. If they aren't and you need to test for whether the inputs are in the desired format as well, repeat the alphanumeric ID characters with a character set instead of . , and throw or something when the required format is not matched:

 const input = ['ThePixies1996', '7ThePixies', 'The-Pixies', 'The-Pixies-1234567', 'The-Pixies/1234567', 'invalid/input/string' ]; function parse(str) { const match = str.match(/^([az\\d-]+?)(?:[\\/-](\\d+))?$/i); if (!match) return 'INVALID'; const [_, alphaNumericId, numericId = ''] = match; return { alphaNumericId, numericId }; } console.log( input.map(parse) );

You can do it without regex in much simpler way

const parse = (data) => {
    let inx = data.lastIndexOf("-")
    if (inx === -1 || isNaN(data.slice(inx))){
        inx = data.lastIndexOf("/")  
    }
    return {
          numericId: data.slice(0, inx),
          alphaNumericId: data.slice(inx+1)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM