What's wrong with this number extracting Regex? - regex

I have a string like the following:
<br><b>224h / 15.45 verbuchte Stunden</b>
I want to extract the numbers and have created the following Regex:
([0-9]\.?[0-9]{0,2})h\s\/\s([0-9]\.?[0-9]{0,2})
But for the preceding string this gives me the numbers 224 and 15 instead of 15.45.
What's wrong with this Regex?

Because you allow only one digit before the dot.
Try this, I used {1,2} as quantifier before the dot, change it to your needs. Probably + would be a better choice, it allows one or more.
([0-9]\.?[0-9]{0,2})h\s\/\s([0-9]{1,2}\.?[0-9]{0,2})
A better regex could be this
([0-9]+(?:\.[0-9]{1,2})?)h\s*\/\s*([0-9]+(?:\.[0-9]{1,2})?)
I made here the complete fraction part optional and require at least one and at most 2 digits after the dot and minimum one before.

The answer is given by stema.
If your regex engine supports character classes it could be a little bit more compact like this:
(\d{1,2}\.?\d{0,2})h\s/\s(\d{1,2}\.?\d{0,2})
\d is a shorthand character class for [0-9]

Related

Multiple {n} quantifiers regex

Is it possible to have multiple quantifiers in a regex?
Say I have the following regex:
[A-Z0-9]{44}|[A-Z0-9]{36}|[A-Z0-9]{30}
I want to match any string which is either 30, 36 or 44 chars long. Is it possible to write this shorter in any way? Something like the following:
[A-Z0-9<]{30|36|44}?
Edit: Seeing the answers I assume there is not really a way in which you can write the above shorter. The best solution would be to solve it programmatically I guess. Thanks for the input.
Brief
Note that your regex performs much better than any other answers you'll get on your question, but since your question is actually about simplifying/shortening your regex, you can use this.
Your original regex (38 characters):
[A-Z0-9]{44}|[A-Z0-9]{36}|[A-Z0-9]{30}
Your original regex with modifications so that we can use it to test against multiline input (44 characters):
^(?:[A-Z0-9]{44}|[A-Z0-9]{36}|[A-Z0-9]{30})$
Code
My original regex (32 characters):
([A-Z0-9]){44}|(?1){36}|(?1){30}
My original regex with modifications so that we can use it to test against multiline input (38 characters):
^(?:([A-Z0-9]){44}|(?1){36}|(?1){30})$
See regex in use here
Explanation
([A-Z0-9]){44}|(?1){36}|(?1){30} Match either of the following
([A-Z0-9]){44} Match any character in the set (A-Z or 0-9) exactly 44 times. This also captures a single character in the set into capture group 1. We will later use this capture group through recursion.
(?1){36} Recurse the first subpattern exactly 36 times
(?1){30} Recurse the first subpattern exactly 30 times
Looks like you want
[A-Z0-9]{30}([A-Z0-9]{6}([A-Z0-9]{8})?)?
This isn't actually simpler, mind you.
You don't need to check your input contains only uppercase letters [A-Z] and digits [0-9] to test whether it is a string. Eliminate [A-Z0-9] part for this reason. Now, you can specify multiple quantifiers as follows:
^(?:.{30}|.{36}|.{44})$
If you need to do that check strictly. You can use this regex without typing [A-Z0-9] three times:
^(?=[A-Z0-9]*$)(?:.{30}|.{36}|.{44})$
You have the [A-Z0-9] part only once and a generic . to check the length of string.

Improve Regex with Groups

Just getting into regex and I am trying to write a regex for a uk national insurance number example ab123456c.
I've currently got this which works
^[jJ]{2}[\-\s]{0,1}[0-9]{2}[\-\s]{0,1}[0-9]{2}[\-\s]{0,1}[0-9]{2}[\-\s]{0,1}[a-zA-Z]$
but I was wondering if there is a shorter version for exmaple
^[jJ]{2} [ [\-\s]{0,1}[0-9]{2} ]{3} [\-\s]{0,1}[a-zA-Z]$
So repeat the [-\s]{0,1}[0-9]{2} 3 by wrapping it in some sort of group [ * ]{3}
If i got you right, your insurance numbers are always two letters, 6 numbers, and a final letter, A,B,C or D? Wouldn't it be the easiest way to try sth. like that
/\w{2}\d{6}[A-D]/
you catch 2 letters at first with \w{2} , then you get 6 numbers with \d{6} and you end with a letter from A to D by [A-D]
Or, if blanks are impontant, try this
/\w{2}\d\d \d\d \d\d [A-D]/
I dont think that shorten it much more would be possible, since when you are trying to use (\d\d ){3} it would only repeat the same pattern three times, e.g. 23 23 23
If you really want to learn RegEx, i suggest you this tutorial, it helped me a lot in the beginning of Regular Expressions
A simple research for a regex tutorial in your favorite search engine (duckduckgo for sure) would give you the answer faster than asking in a forum!
So what you are looking for is a non-capturing group (?:...). You can rewrite your pattern like this:
^[jJ]{2}(?:[-\s]?[0-9]{2}){3}[-\s]?[a-zA-Z]$
or like this if you use a case insensitive flag/option:
^J{2}(?:[-\s]?[0-9]{2}){3}[-\s]?[A-Z]$
An other possible way consists to remove all that is not a letter or a digit before (and eventually to use an uppercase function). Then you only need:
^J{2}[0-9]{6}[A-Z]$
As an aside, I don't understand why you start your pattern with J for the first two letters, since many others letters are allowed according to this article: https://en.wikipedia.org/wiki/National_Insurance_number
Other thing, short and efficient are two different things in computing.
for example this pattern will be efficient too and more restrictive:
^(?!N[KT]|BG|GB|[KT]N|ZZ)[ABCEGHJ-PRSTW-Z][ABCEGHJ-NPRSTW-Z][0-9][0-9][-\s]?[0-9][0-9][-\s]?[0-9][0-9][-\s]?[A-D]$
A shorter version:
/^j{2}(?:[-\s]?\d{2}){3}[-\s]?[a-zA-Z]$/i
See the regex online demo
Note that
you do not need to escape - inside the character class if it is at the beginning or end of the class (see Metacharacters Inside Character Classes)
you can use a \d as a shorthand character class for a digit (see Shorthand Character Classes)
{0,1} limiting quantifier can usually be represented as a ? quantifier (1 or zero occurrences) (see Limiting Repetition)
The /i (or inline modifier version (?i) - depending on the engine) can be used to turn [jJ] to just j or J (see Specifying Modes Inside The Regular Expression)
A limiting quantifier can be applied to a whole (better non-capturing) group: (?:[-\s]?\d{2}){3} (see Limiting Repetition)

Regular Expressions, getting digit after second occurence of dot

I want to get a number after second dot in a string like that :
4.5.3. Some kind of question ? but input string might look like this as well 41.53.32. Some kind of question ? so im aiming for 3 in the first example and 32 in second example.
I'm trying to do it with
(?<=(\.\d\.))[0-9]+
and it works on 1st example, but when im trying to add (?<=(\.\d+\.))[0-9]+
it doesn't work at all.
If there is always a dot after the final number then you can use the following expression:
\d+(?=\.(?:[^\d]|$))
This will match one or more digits \d+ which are followed by a dot . then something that is either not a number [^\d] of the end-of-string $, i.e. (?=\.(?:[^\d]|$)).
Regex101 Demo
If you use PERL or PHP, you can try this pattern:
(?:\d+\.){2}\K\d+
The simplest complete answer is probably something like this:
(?<=^(?:[^.]*\.){2})\d+
If you're at all worried about performance, this one will be slightly faster:
^(?:[^.]*\.){2}(\d+)
This one will capture the desired value in capturing group 1.
If you are using an engine that doesn't support variable-length lookbehind, you'll need to use the second version.
If you wish, you can replace [^.] with \d, to only match digits.
(\d+.\d+.)\K\d+
Match digits dot digits dot digits, with the first section as a group not selected.
(?:(?:.*\.)?){2}(\d+)
the following regex should work for your use case.
check it out here

Regex for two digits in any order

I need a regex that will match a string as long as it includes 2 or more digits.
What I have:
/(?=.*\d)(?=.*\d)/
and
/\d{2,}/
The first one will match even if there is one digit, and the second requires that there are 2 consecutive digits. I have tried to combine them in different ways to no avail.
You can do much simpler :
/\d\D*\d/
You can use the following expression:
.*\d.*\d.*
This will match anything that has two digits in it, anywhere. Regardless of where the numbers are. Example here.
You can also do it like this, using ranges:
.*[0-9].*[0-9].*
Link.
You may also consider using this:
\D*\d\D*\d
The \D will match anything that is not a digit character
It depends on your applications language, but this regex is the most general:
^(?=.*\d.*\d)
Not all application languages consider partial matches as "matching"; this regex will match no matter where in the input the two digits lie.
grep -E ".*[0-9].*[0-9].*" filename
You can use the following depending on the use case:
^(?=(?:\D*\d){2}).* - The restriction is implemented with a positive lookahead (anchored at the start of string) that requires any two (or more) digits anywhere inside the string (and the regex flavor supports lookaheads) - Regex demo #1
^([^0-9]*[0-9]){2}.* - The regex matches a string that starts with two sequences of any non-digit chars followed with a digit char and then contains any text (this pattern is POSIX ERE compliant, to make it POSIX BRE compliant, use ^\([^0-9]*[0-9]\)\{2\}.*) - Regex demo #2
\d\D*\d - in case you simply want to make sure there is a digit + zero or more chars other than digits followed with a digit and the method you are using allows partial matches - Regex demo #3.
The first approach is best when you already have a complex pattern and you need to add an extra constraint.
The second one is good for POSIX regex engines.
The third one is best when you implement complex if-else logic for password and other validations with separate error messages per issue.
try this.
[0-9].{2}
this will help to u

How to optimise this regex to match string (1234-12345-1)

I've got this RegEx example: http://regexr.com?34hihsvn
I'm wondering if there's a more elegant way of writing it, or perhaps a more optimised way?
Here are the rules:
Digits and dashes only.
Must not contain more than 10 digits.
Must have two hyphens.
Must have at least one digit between each hyphen.
Last number must only be one digit.
I'm new to this so would appreciate any hints or tips.
In case the link expires, the text to search is
----------
22-22-1
22-22-22
333-333-1
333-4444-1
4444-4444-1
4444-55555-1
55555-4444-1
666666-7777777-1
88888888-88888888-1
1-1-1
88888888-88888888-22
22-333-
333-22
----------
My regex is: \b((\d{1,4}-\d{1,5})|(\d{1,5}-\d{1,4}))-\d{1}\b
I'm using this site for testing: http://gskinner.com/RegExr/
Thanks for any help,
Nick
Here is a regex I came up with:
(?=\b[\d-]{3,10}-\d\b)\b\d+-\d+-\d\b
This uses a look-ahead to validate the information before attempting the match. So it looks for between 3-10 characters in the class of [\d-] followed by a dash and a digit. And then after that you have the actual match to confirm that the format of your string is actually digit(dash)digit(dash)digit.
From your sample strings this regex matches:
22-22-1
333-333-1
333-4444-1
4444-4444-1
4444-55555-1
55555-4444-1
1-1-1
It also matches the following strings:
22-7777777-1
1-88888888-1
Your regexp only allows a first and second group of digits with a maximum length of 5. Therefore, valid strings like 1-12345678-1 or 123456-1-1 won't be matched.
This regexp works for the given requirements:
\b(?:\d\-\d{1,8}|\d{2}\-\d{1,7}|\d{3}\-\d{1,6}|\d{4}\-\d{1,5}|\d{5}\-\d{1,4}|\d{6}\-\d{1,3}|\d{7}\-\d{1,2}|\d{8}\-\d)\-\d\b
(RegExr)
You can use this with the m modifier (switch the multiline mode on):
^\d(?!.{12})\d*-\d+-\d$
or this one without the m modifier:
\b\d(?!.{12})\d*-\d+-\d\b
By design these two patterns match at least three digits separated by hyphens (so no need to put a {5,n} quantifier somewhere, it's useless).
Patterns are also build to fail faster:
I have chosen to start them with a digit \d, this way each beginning of a line or word-boundary not followed by a digit is immediately discarded. Other thing, using only one digit, I know the remaining string length.
Then I test the upper limit of the string length with a negative lookahead that test if there is one more character than the maximum length (if there are 12 characters at this position, there are 13 characters at least in the string). No need to use more descriptive that the dot meta-character here, the goal is to quickly test the length.
finally, I describe the end of string without doing something particular. That is probably the slower part of the pattern, but it doesn't matter since the overwhelming majority of unnecessary positions have already been discarded.