Regex: Separate a string of characters with a non-consistent pattern (Oracle) (POSIX ERE)

Viewed 79

EDIT: This question pertains to Oracle implementation of regex (POSIX ERE) which does not support 'lookaheads'

I need to separate a string of characters with a comma, however, the pattern is not consistent and I am not sure if this can be accomplished with Regex.

Corpus: 1710ABCD.131711ABCD.431711ABCD.41711ABCD.4041711ABCD.25

The pattern is basically 4 digits, followed by 4 characters, followed by a dot, followed by 1,2, or 3 digits! To make the string above clear, this is how it looks like separated by a space 1710ABCD.13 1711ABCD.43 1711ABCD.4 1711ABCD.404 1711ABCD.25

So the output of a replace operation should look like this:

1710ABCD.13,1711ABCD.43,1711ABCD.4,1711ABCD.404,1711ABCD.25

I was able to match the pattern using this regex:

(\d{4}\w{4}\.\d{1,3})

It does insert a comma but after the third digit beyond the dot (wrong, should have been after the second digit), but I cannot get it to do it in the right position and globally.

Here is a link to a fiddle https://regex101.com/r/qQ2dE4/329

3 Answers

All you need is a lookahead at the end of the regular expression, so that the greedy \d{1,3} backtracks until it's followed by 4 digits (indicating the start of the next substring):

(\d{4}\w{4}\.\d{1,3})(?=\d{4})
                     ^^^^^^^^^

https://regex101.com/r/qQ2dE4/330

To expand on @CertainPerformance's answer, if you want to be able to match the last token, you can use an alternative match of $:

(\d{4}\w{4}\.\d{1,3})(?=\d{4}|$)

Demo: https://regex101.com/r/qQ2dE4/331

EDIT: Since you now mentioned in the comment that you're using Oracle's implementation, you can simply do:

regexp_replace(corpus, '(\d{1,3})(\d{4})', '\1,\2')

to get your desired output:

1710ABCD.13,1711ABCD.43,1711ABCD.4,1711ABCD.404,1711ABCD.25

Demo: https://regex101.com/r/qQ2dE4/333

In order to continue finding matches after the first one you must use the global flag /g. The pattern is very tricky but it's feasible if you reverse the string.

Demo

var str = `1710ABCD.131711ABCD.431711ABCD.41711ABCD.4041711ABCD.25`;

// Reverse String
var rts = str.split("").reverse().join("");

// Do a reverse version of RegEx
/*In order to continue searching after the first match,
use the `g`lobal flag*/
var rgx = /(\d{1,3}\.\w{4}\d{4})/g;

// Replace on reversed String with a reversed substitution
var res = rts.replace(rgx, ` ,$1`);

// Revert the result back to normal direction 
var ser = res.split("").reverse().join("");

console.log(ser);

Related