Home > Software engineering >  Regex - Capture after 2nd occurance of character
Regex - Capture after 2nd occurance of character

Time:11-16

I have a list of numbers

1.01.01.01

1.01.01.02

1.01.02.03

I need to add 1 to the number after the 2nd occurance of '.0':

1.01.02.01

1.01.02.02

1.01.03.03

I am using javascript. I have tried a few things, but I just get so confused with regex haha.


I have been playing, and split might be the way to go here, thanks Richard. Anyone happen to know increment 1 on a 01 in a string, or will I need to break down the string and turn it to an integer. first?

CodePudding user response:

You may use this code snippet that does the job in these steps:

  1. Splits input string by .0
  2. Converts 2nd element to Integer and increments it by 1
  3. Stores resulting elements in an array ret
  4. Joins elements of ret with .0 again and saves new String in result array
  5. Finally displays result array

Code:

const arr = ['1.01.01.01','1.01.01.02', '1.01.02.03'];
const delim = '.0';
var result = [];

arr.forEach(str => {
  ret = [];
  str.split(delim).forEach((el, i) => 
     ret.push(i==2 ? parseInt(el) 1 : el)
  );
  result.push(ret.join(delim));
});

console.log(result);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

A replace based approach is in need of a more complex capturing regex like ... /^((?:.*?\.0){2})(\d )(.*)/ ... and a replacer function as its second argument.

The regex ... /^((?:.*?\.0){2})(\d )(.*)/ ... reads like this ...

  1. Part 1: ^( (?:.*?\.0){2} )

    • From line start ^ capture ( ... ) the following match ...
    • (?: ... ){2} ... twice {2} a not captured ?: group ( ... ) of following pattern ...
    • .*?0 ... anything .* in a non ? greedy way until a Dot-Zero sequence .0 occurs.
  2. Part 2: (\d )

    • Capture ( ... ) at least one digit \d.
  3. Part 3: (.*)

    • Capture ( ... ) anything .* greedy until the end of the string.

The related replacer function is the callback of replace and gets passed as arguments the entire match (1st argument) followed by each captured value as separate argument, starting with the first and ending with the last capture.

Thus for the given example the replacer function's argument names (which can be freely chosen) and precedence are ... (match, leading, digits, trailing) ... where digits is the 2nd capture group, the digit (sequence) which the OP wants to become an incremented integer.

A solution then might look similar to the next provided example code ...

const sampleData = [
  '1.01.01.02',
  '1.01.02.03',

  '1.01.0x.04',
  '1.01.0x.0x',

  '1.01.001.01.07.08.09',
  '1.01.013.03.01200230',
];
// see ... [https://regex101.com/r/60omn1/2]
const regXCapture = (/^((?:.*?\.0){2})(\d )(.*)/);

console.log(
  sampleData, '=>',

  sampleData.map(item =>
    item.replace(
      regXCapture,
      (match, leading, digits, trailing) => [
        leading,
        parseInt(digits, 10)   1,
        trailing,
      ].join('')
    )
  )
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

A split and/but non regex based approach can be implemented as straightforward as the following code (of cause having no control over the validity of the parsed 3rd argument which is assumed to be a digit (sequence)) ...

const sampleData = [
  '1.01.01.02',
  '1.01.02.03',

  '1.01.0x.04',
  '1.01.0x.0x',

  '1.01.001.01.07.08.09',
  '1.01.013.03.01200230',
];

console.log(
  sampleData, '=>',

  sampleData.map(item => {
    const [leadingA, leadingB, digits, ...trailing] = item.split('.0');
    return [
      leadingA, leadingB, (parseInt(digits, 10)   1), ...trailing
    ].join('.0');
  })
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related