>/h.llo/ the '.' matches any one character other than a new line character... matches 'hello', 'hallo' but not 'h llo' in the cheatsheet is false. ( https://regexr.com/4tc48 ) `.` can match any character except linebreaks (including whitespace)
Show HN: Regex Cheatsheet
101–110 of 135 posts
Re: Show HN: Regex Cheatsheet
#102I use regex a lot but deliberately keep it simple. One thing that confounded me often was positive and negative look-arounds. I always got the expressions mixed up, until I just put the expressions into a table like this... look-behind | look-ahead ------------------------------------ positive (? It's not hard, but for whatever reason my brain had trouble remembering the usage because every time I looked it up, each…
Maybe it's easier to remember that lookbehinds are evil from an implementation standpoint, and even in Perl have arbitrary limitations. If you see lookbehinds, look away! If you see lookaheads, go ahead.
Re: Show HN: Regex Cheatsheet
#103I use regex a lot but deliberately keep it simple. One thing that confounded me often was positive and negative look-arounds. I always got the expressions mixed up, until I just put the expressions into a table like this... look-behind | look-ahead ------------------------------------ positive (? It's not hard, but for whatever reason my brain had trouble remembering the usage because every time I looked it up, each…
Maybe it's easier to remember that lookbehinds are evil from an implementation standpoint, and even in Perl have arbitrary limitations. If you see lookbehinds, look away! If you see lookaheads, go ahead.
To handle a lookbehind, you really only need to occasionally 'AND' together some states (not an operation you would normally do in a standard NFA whether Glushkov or Thompson). To handle lookaheads... well, it gets ugly.
Re: Show HN: Regex Cheatsheet
#104Re: Show HN: Regex Cheatsheet
#105OK, these kinds of regex tools get posted quite often. I get it, regex is very confusing at first. And some of these use-cases result in rather complex expressions nobody should be forced to write from scratch (you are still remembering to write unit tests for them though, right?) But as someone who actually knows [some flavours of] regex fairly well, what I would really like, is a reference that covers all the subtl…
1. Stick to using the lowest common denominator like you did for case insensitivity.
2. If that becomes too cumbersome, then consider whether regex is the right tool for the job. Maybe you can use e.g Python/your favorite language with a known regex standard.
3. If there are no other tools and you're stuck with whatever flavor of regex one particular thing supports, only then invest time in learning the details. There is probably a book out there with the details even if there's no webpage.
Then pray you never get to step 3 :)
Re: Show HN: Regex Cheatsheet
#106Earlier quoted context omitted.
Balanced paranthesis are not a regular language, so it s theoretically imposdible to match them with regular expressions. In practice, most regexp implemenations you see are more powerful then regular expressions. For instance, .net has a balancing groups feature [0] for exactly this usecase. [0] https://regular-expressions.mobi/balancing.html?wlr=1
The regex I've copy-pasted is this: $str = "(this is inside a bracket (and this is nested or (double nested)))"; do { preg_match_all('~\(((?:[^\(\)]++|(?R))*)\)~', $str, $matches); echo $str = $matches[1][0] ?? '', "\n"; } while($str); Outputs this [1]: > this is inside a bracket (and this is nested or (double nested)) > and this is nested or (double nested) > double nested You're right that there is more processing…
First, the "~" characters aren't really part of the regular expression. As far as I can tell, they are delimeters to mark the start/stop of this. Often you will see "/" used for this purpose.
Next is:
\( ... \)
This matches a pattern that starts with the literal character '(' and ends with ')', where what comes between them matches the elided portion. Since parantheses have special meaning in regex, we need to espace these characters.Continueing are way inward, we see:
( ... )
Which is non-escaped parentheses. This is a pattern group, and is used to treat the pattern within it as a single unit. For example the pattern "ab" would match abbb, but not ababab, because the "" (repeat) modifier only applies to "b". However "(ab)" matches "ababab", but not "abbbb". In this case, there is no modifier, so these parantheses have no effect on what string matches the overall expression. However, many implementations also use paranthesis to define matching groups, which means they will return whatever is captured within the parantheses as a match. Essentially, the pattern of: \(( ... )\)
means, find a string that starts with '(' and ends with ')', and pull out everything in the middle.Next comes a simmilar construct:
(?:...)
There are 2 things going on here. This matches whatever is being elided by ..., however the library does not return it a separate result. This is used when you need to group things together within a regular expression, but do not want that specific grouping returned as part of the result. The "" here means that the entire pattern can be matched any number (including 0) of times, and should be matched as many times as possible.Next is
[^\(\)]
The square brackets indicate that you should match any character within a particular set. The "^" in the beggining of square brackets means that you are inverting the selection, so you will match any character except those specified. The remaining characters, are paranthesis literals.The first "+" indicates that the pattern should match 1 or more of the previus entity. In the case of [^\(\)]+, this would mean that it can match one or more non paranthesise characters.
The second "+" is different. Since quantifiers are not allowed to follow other quantifiers, the above meaning does not apply, and the langauge was allowed to overload the symbol. This modifies the previous quantifier to be greedy, meaning it will consume as many characters as possible (e.g. all characters until it hits a parenthesis). I don't think this is technically needed in this case, but probably improves efficiency.
The next component is "|", which means to match either the pattern on the left, or the right.
The next step is not a regular expression, but one of those "more powerful" additions I mentioned. (?R) is a recursive match, and matches whatever the overall expression matches. Eg, when your expression runs into a nested paranthesis, it recurses and parses the substring as a balanced paranthesis string.
Putting this all together (and ignoring whitespace while adding comments; as most major regex engines have an option to allow you to do):
\( #Start with an open parathesis
( #This is the beginning of the region I want to extract
(?: #Group the following pattern together, but don't save the matching substring
[^\(\)]++ # Match until a parenthesis character, assuming that would match at least 1 character
| # Or
(?R) #Match a string with balanced paranthesis (assuming that is what the overall regex does).
)* #Repeat the preceeding pattern as many times as nessasary
) #End the region I want to extract
\) #The next character should be a close paranthesis.
Looking at an example of this: (aaa(bbb))
First, we match "(". Then we try to match (?:[^\(\)]++|(?R))* as a matching group.This matches [^\(\)]++|(?R) as many times as necessary.
At this point, are remaing string is "aaa(bbb))".
Since the pattern we are matching this against is an "|" pattern, we have 2 options: we can either match against: [^\(\)]++, which would match "aaa", or we could match against (?R), which would fail, since the first character is not '('. As such, we match "aaa". Since this grouping was defined using (?:) instead of (), we do not save "aaa" as a separate result
Next, since the group is modified by "*", we can either match another instance of it, or move on to match the closing ")". The next character is not ')', so are only option is to match another instance of "[^\(\)]++|(?R)"
At this point the remaining string is (bbb)), so [^\(\)]++ fails to match, since it requires at least one character before the '('. However, now (?R) works and matches (bbb).
Now are remaining string is ")" and our options are again to match either "[^\(\)]++|(?R)", or ')'. At this point, neither [^\(\)]++ nor (?R) work, so the only option is to leave the repetition and match the closing ')'.
Re: Show HN: Regex Cheatsheet
#107Earlier quoted context omitted.
Maybe it's easier to remember that lookbehinds are evil from an implementation standpoint, and even in Perl have arbitrary limitations. If you see lookbehinds, look away! If you see lookaheads, go ahead.
Oddly, lookbehinds are evil only in a specific backtracking world. We never got around to implementing arbitrary lookarounds in Hyperscan ( https://github.com/intel/hyperscan ) but if we had done something in the automata world to handle lookaround, lookbehinds are way easier than lookaheads. To handle a lookbehind, you really only need to occasionally 'AND' together some states (not an operation you would normally d…
Re: Show HN: Regex Cheatsheet
#108Re: Show HN: Regex Cheatsheet
#109Earlier quoted context omitted.
Honestly, as a noob, this is one of the biggest reasons I have such a hard time deciding to learn regex. Python flavor would probably be different than PCRE, which is probably different than JS flavor. Even worse is that it might be too late to standardize all the regex flavors because there is already so much written in different regex flavors that it just costs too much for them to become obsolete in the future. Th…
> Honestly, as a noob, this is one of the biggest reasons I have such a hard time deciding to learn regex. Clear your afternoon, and just learn it. Seriously, it takes a couple of hours at best and then - BOOM - you're done for the rest of your life.
Re: Show HN: Regex Cheatsheet
#110Thumbs up for the relatable domain name.