Javascript: Map string using regex and include only matched groups

59 views Asked by At

I have some files that are named according to their content. Some files are single parts and some contain multiple parts. I cannot change this structure unfortunately.

Using JavaScript, I would like to use a regex to match the filename, and then use any matched groups to create a new filename. The regex itself only partially matches the filename.

For example:

From To
MyTestString1-id1p01&p02.Part1And2.txt 1-2. Part1And2.txt
MyTestString2-id1p03.Part3.txt 3. Part3.txt
MyTestString3-id1p04.Part4.txt 4. Part4.txt

I tried using a regex to match the filename: (?:p(\d+))(?:&p(\d+))?\.(.+)\.

This works and gives me the matches I want:

MyTestString1-id1p01&p02.Part1And2.txt -> [p01&p02.Part1And2., 01, 02, Part1And2]
MyTestString2-id1p03.Part3.txt -> [p03.Part3., 03, Part3]
MyTestString3-id1p04.Part4.txt -> [p04.Part4., 04, Part4]

However I can't find a nice way to then map to the string I want. I want something like $1-$2. $3

But string.replace only replaces the matches, and still includes the rest of the string. So I end up with: MyTestString1-id101-02. Part1And2txt instead of 1-2. Part1And2.txt. Which makes sense, it's doing a replace where I need something more like a template.

And for others that don't have a second part I get: MyTestString2-id103-. Part3txt which contains the - that I don't want.

Is there something similar to string.replace using only the replacement string? And is there a way to optionally include a separator for groups that may exist and exclude them if they don't?

Also note the filenames are much large than in my example, I just cut them short as I'm ignoring them.

Thanks in advance.

1

There are 1 answers

2
Wiktor Stribiżew On

You can use

p(\d+)(?:&p(\d+))?\.(.+\.[^.]*)$

See the JS demo code below:

const texts = ['MyTestString1-id1p01&p02.Part1And2.txt', // 1-2. Part1And2.txt
'MyTestString2-id1p03.Part3.txt', //    3. Part3.txt
'MyTestString3-id1p04.Part4.txt'] //    4. Part4.txt
const re = /p(\d+)(?:&p(\d+))?\.(.+\.[^.]*)$/;
for (const s of texts) {
  const [_,num1,num2,filename] = re.exec(s)
  result = `${Number(num1)}` + (num2 ? `-${Number(num2)}. `:'. ') + filename;
  console.log(s, '=>', result);
}

Here is the regex demo

Note that (.+\.[^.]*)$ matches and captures into Group 3 one or more characters other than line break chars, as many as possible and then a . and then zero or more chars other than a . till end of string.