Regex Optionally Match a Pattern Multiple Times

Regex Optionally match a pattern multiple times

You may validate the string with a positive lookahead triggered at the start of the string, and then match all numbers from the start up to the currency value once the validation succeeds:

'~(?:\G(?!^)|^(?=\d+\.\d+ \d+\.\d+ \d+(?:\.\d+)?(?: \d+)* \$\d))\s*\$?\K\d+(?:\.\d+)?~'

See the regex demo

Details

  • (?:\G(?!^)|^(?=\d+\.\d+ \d+\.\d+ \d+(?:\.\d+)?(?: \d+)* \$\d)) - either the end of the previous match (\G(?!^)) or start of a string (^) that is followed with

    • \d+\.\d+
    • - a space
    • \d+\.\d+
    • - a space
    • \d+ - 1+ digits
    • (?:\.\d+)? - an optional fractional part
    • (?: \d+)* - 0+ sequences of a space followed with 1+ digits
    • - space
    • \$\d - a $ and a digit.
  • \s* - 0+ whitespaces
  • \$? - an optional $ char
  • \K - match reset operator
  • \d+(?:\.\d+)? - an int/float number (1+ digits followed with an optional sequence of . and 1+ digits).

PHP demo:

$strs = ['0.91 0.45 0.69 58 47 45 23 83 90 $595 NO IDL','0.91 0.45 0.69 58 47 45 $595 NO IDL','0.91 0.45 0.69 0.63 58 47 45 $595 NO IDL'];
$rx = '~(?:\G(?!^)|^(?=\d+\.\d+ \d+\.\d+ \d+(?:\.\d+)?(?: \d+)* \$\d))\s*\$?\K\d+(?:\.\d+)?~';
foreach ($strs as $s) {
echo "$s:\n";
if (preg_match_all($rx, $s, $matches)) {
print_r($matches[0]);
echo "---------\n";
} else {
echo "NO MATCH!!!\n---------\n";
}

}

Output:

0.91 0.45 0.69 58 47 45 23 83 90 $595 NO IDL:
Array
(
[0] => 0.91
[1] => 0.45
[2] => 0.69
[3] => 58
[4] => 47
[5] => 45
[6] => 23
[7] => 83
[8] => 90
[9] => 595
)
---------
0.91 0.45 0.69 58 47 45 $595 NO IDL:
Array
(
[0] => 0.91
[1] => 0.45
[2] => 0.69
[3] => 58
[4] => 47
[5] => 45
[6] => 595
)
---------
0.91 0.45 0.69 0.63 58 47 45 $595 NO IDL:
NO MATCH!!!
---------

Regex match a pattern occurring multiple times in a string

You can use

^[0-9]+:[0-9]+, 80:[0-9]+, 443:[0-9]+(, [0-9]+:[0-9]+)+,$

See the regex demo.

Also, consider the awk solution like

awk '/^[0-9]+:[0-9]+(, [0-9]+:[0-9]+)+,$/ && /80/ && /443/' file

See the online demo:

#!/bin/bash
s='0:0, 80:3, 443:0, 8883:0, 9000:0, 9001:0,
0:0, 80:0, 443:1, 8883:0, 9000:0, 9001:0,
0:0, 80:0, 443:0, 8883:0, 9000:0, 9001:0,
0:0, 80:3, 443:1, 8883:0, 9000:0, 9001:0,
0:0, 443:0, 8883:0, 9000:0, 9001:0,
0:0, 80:0, 8883:0, 9000:0, 9001:0,
0:0, 8883:0, 9000:0, 9001:0,'
awk '/^[0-9]+:[0-9]+(, [0-9]+:[0-9]+)+,$/ && /80/ && /443/' <<< "$s"

Output:

0:0, 80:3, 443:0, 8883:0, 9000:0, 9001:0,
0:0, 80:0, 443:1, 8883:0, 9000:0, 9001:0,
0:0, 80:0, 443:0, 8883:0, 9000:0, 9001:0,
0:0, 80:3, 443:1, 8883:0, 9000:0, 9001:0,

Regex with multiple optional groups

Try

^(?:.*?(?P<left>&L.[^&]*))?(?:.*?(?P<center>&C.[^&]*))?(?:.*?(?P<right>&R.[^&]*))?.*$

regex101 demo.


Explanation of the left group (center and right are pretty much the same):

(?:
.*? # consume any preceding text
(?P<left> # then capture...
&L # "&L" literally
. # the character after that
[^&]* # and then everything up to the next "&" character
)
)? # and make the whole thing optional.

P.S.: Your pattern didn't make any of the groups optional. You should've put the ? after the group, like (?P<left>&L.+)? .


UPDATE

Since the groups aren't supposed to end at the next & character, you can try the pattern

(?P<left>&L.+?)?(?P<center>&C.+?)?(?P<right>&R.+?)?$

instead. All I did was to make all groups optional by adding a ?, and forcing the pattern to consume the entire string by putting the anchor $ at the end.

regex101 demo.

Update: (?:&L(?P<left>.+?))?(?:&C(?P<center>.+?))?(?:&R(?P<right>.+?))?$ won't capture the &L, &C and &R bits.

Regex how to match an optional character

Use

[A-Z]?

to make the letter optional. {1} is redundant. (Of course you could also write [A-Z]{0,1} which would mean the same, but that's what the ? is there for.)

You could improve your regex to

^([0-9]{5})+\s+([A-Z]?)\s+([A-Z])([0-9]{3})([0-9]{3})([A-Z]{3})([A-Z]{3})\s+([A-Z])[0-9]{3}([0-9]{4})([0-9]{2})([0-9]{2})

And, since in most regex dialects, \d is the same as [0-9]:

^(\d{5})+\s+([A-Z]?)\s+([A-Z])(\d{3})(\d{3})([A-Z]{3})([A-Z]{3})\s+([A-Z])\d{3}(\d{4})(\d{2})(\d{2})

But: do you really need 11 separate capturing groups? And if so, why don't you capture the fourth-to-last group of digits?

Regex match pattern with optional character and min/max length

You may use this regex with gnu grep using -P (PCRE):

grep -P '^X(?!([^-]*-){2})(?=[^A-Z]*[A-Z])[A-Z\d-]{3,6}$' file

XABC
XA-BC8D
X-ABC
XB72D-

RegEx Demo

RegEx Details:

  • ^: Start
  • X: Match letter X
  • (?!([^-]*-){2}): Negative lookahead to assert that there are never more than one hyphens ahead
  • (?=[^A-Z]*[A-Z]): Positive lookahead to assert presence of at least one uppercase letter ahead
  • [A-Z\d-]{3,6}: Match an uppercase letter or digit or - 3 to 6 times
  • $: End

If you don't have gnu grep installed then you may consider this awk:

awk -F- 'NF<3 && /^X[A-Z0-9-]{3,6}$/ && /.[A-Z]/' file

XABC
XA-BC8D
X-ABC
XB72D-

Regex optional matching for multiline patterns

Replace match of [\n\r]+(?:[-]+[\n\r]+)?\s*junkhere:\s*[\n\r][\s\S]* with empty string.

Regular expression visualization


Test it here: http://regexr.com?37edu and here: http://regexr.com?37ee1


In Java you have to double escape characters:

= text.replaceAll("[\\n\\r]+(?:[-]+[\\n\\r]+)?\\s*junkhere:\\s*[\\n\\r][\\s\\S]*", "");

How to add an optional string or end the string with Regex?

Try this pattern: ^\$\d+(?:\.\d{2})?$

See Regex Demo

Explanation

  • ^: Start of the string.
  • \$: Match with the character $.
  • \d+: Match with one or more digits between 0-9.
  • (?:: Start of the non-captured group.
  • \.: Match with the dot character.
  • \d{2}: Match exactly two digits.
  • ): End of the group.
  • ?: Make everything in the group optional.
  • $: End of the string.

Note: the $ and . character in regex means respectively end of the string and everything, so if we want to capture exactly the $ character (not the end of the string) we should escape those characters.

regexp: multiline, non-greedy match until optional string

Use

(?s)\AKey1:\n(?P<Key1>.*)Key2:\n(?P<Key2>.*?)(?:OptionalKey3:\n(?P<OptionalKey3>.*))?\z

See regex proof.

EXPLANATION

--------------------------------------------------------------------------------
(?s) set flags for this block (with . matching
\n) (case-sensitive) (with ^ and $
matching normally) (matching whitespace
and # normally)
--------------------------------------------------------------------------------
\A the beginning of the string
--------------------------------------------------------------------------------
Key1: 'Key1:'
--------------------------------------------------------------------------------
\n '\n' (newline)
--------------------------------------------------------------------------------
(?P<Key1> group and capture to "Key1":
--------------------------------------------------------------------------------
.* any character (0 or more times (matching
the most amount possible))
--------------------------------------------------------------------------------
) end of "Key1"
--------------------------------------------------------------------------------
Key2: 'Key2:'
--------------------------------------------------------------------------------
\n '\n' (newline)
--------------------------------------------------------------------------------
(?P<Key2> group and capture to "Key2":
--------------------------------------------------------------------------------
.*? any character (0 or more times (matching
the least amount possible))
--------------------------------------------------------------------------------
) end of "Key2"
--------------------------------------------------------------------------------
(?: group, but do not capture (optional
(matching the most amount possible)):
--------------------------------------------------------------------------------
OptionalKey3: 'OptionalKey3:'
--------------------------------------------------------------------------------
\n '\n' (newline)
--------------------------------------------------------------------------------
(?P<OptionalKey3> group and capture to "OptionalKey3":
--------------------------------------------------------------------------------
.* any character (0 or more times
(matching the most amount possible))
--------------------------------------------------------------------------------
) end of "OptionalKey3"
--------------------------------------------------------------------------------
)? end of grouping
--------------------------------------------------------------------------------
\z the end of the string


Related Topics



Leave a reply



Submit