Fun with regular expressions: part I
yurichev.com
yurichev.com
>using the standard RE, it's impossible to match only DD-MM-YYYY or DDMMYYYY strings without matching DD-MMYYYY or DDMM-YYYY, because it's impossible to represent this in DFA form.
And then there is the reader comment that finds a DFA for this particular problem but then wonders about another:
> now whether one could also accept YYYY-MM-DD/YYYYMMDD format with the same regexps, it might require some sort of deeper magic and back-tracking
Regular languages are closed under union and there is even a straightforward translation to regular expressions (the | operator). Am I really missing something here? It has been a long time since I took a compiler course, but I would be damned.
They are also closed under difference, ie R0 - R1, which means accept all the strings accepted by R0 that aren't accepted by R1. Its very useful. For example, a variable is a token that isn't a keyword can be written succinctly as:
([a-z_][a-z_0-9]*) - (if|then|else|while|for)
Sadly, it was not part of the original re syntaxes so while common now it's not so well known, and the syntax varies wildly. For example, in VIM the above is: [a-z_][a-z_0-9]*\(if\|then\|else\|while\|for\)\@<!
In Python and other pcre based matches like Perl it would be: [a-z_[a-z_][a-z_0-9]*(?<!if|then|else|while|for)
They are also closed under conjunction, eg R0 & R1 matches strings that match both R0 and R1. Again it wasn't there in the first re packages and confusingly it (and difference) is called an "assertion" now. But there isn't a lot of difference between them and '|' - they are all just ways of composing regular expressions.A backref only matches the exact occurance, but here we can abstract the months and year variables and do the duplication with variables. In shell syntax just expand ${MM} and ${YYYY}, in C strlcpy the parts together to arrive at
[0123][0-9](-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(19|20)[0-9]{2}|(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(19|20)[0-9]{2})
I use a permanent marker on a 3x5 index card, and write the command and key combo in black, and then a very "simple" explanation in blue. For instance, "SWIPER SEARCH" "C-c C-s" "inside files". or "DEFT SEARCH" "C-c n d" "across files".
Those index cards get pinned on my home office wall above my main monitor screen. Seems to help a bit for me, not sure if it would for other folks.
Here's a pic for the visually inclined! https://imgur.com/gallery/zlY5wYH
To remember notions, a necessary but less noble capacity, we have invented tools well past the Memex. To be "smart", not yet.
.?|(..+?)\\1+
Which is used for primality checking (applied to the input string length).It's not that hard to understand compared to some others, but being able to do those types of computations with regex is really mind-blowing to me.
More info: https://swtch.com/~rsc/regexp/regexp1.html
“Regular Expression” is just the name for the grammar/formal language model that REs present. REs are a useful way to encode DFAs, but not all things that can be expressed using RE formal-language are DFAs.
Some REs (i.e. the “Perl-compatible” or “extended” Regular Expressions) are Nondeterministic Finite-state Automata or “NFAs”. This doesn’t change the fact that the language used to express them makes them Regular Expressions.
I think it's about descriptivism vs prescriptivism. "Regular expression" did start life with a technical meaning, according to which REs had equivalent expressive power to DFAs. The term has since been appropriated and diluted by other languages, and it is not entirely unreasonable to (though I prefer not to) take "regular expression" to mean "whatever programming languages present as regular expression"; but I think it's not quite right to say that someone is confused who believes in maintaining the original distinction.
When it comes to actual semantic issues like this one, I think that invoking "p vs d" just muddies the waters, because such issues should be examined on a case-by-case basis.
This issue specifically is quite akin to the "literally" case: different instances of usage of the same phrase have (almost) opposite meanings:
See https://en.wiktionary.org/wiki/literally and https://en.wikipedia.org/wiki/Chomsky_hierarchy
I think it's fair to say the Perl-style semantics are just wrong, because there's no way to use them without being confusing.
> Some REs (i.e. the “Perl-compatible” or “extended” Regular Expressions) are Nondeterministic Finite-state Automata or “NFAs”.
That those engines are implemented using an NFA or a DFA does not actually matter for the question of being regular or not. A given pattern may be Regular while another may not be. There are multiple technical reasons these engines are built on NFA's and not DFA's, supporting non-regular expressions is one, but not the only, reason.
Ironically the library called "PCRE" or "Perl-compatible Regular Expressions" is in-fact not "Perl-compatible" (nor regular). It is at the same time both named "Perl-compatible" and absolutely not Perl-compatible. Both PCRE library and the Perl language have evolved and added mutually incompatible features which results in a valid PCRE matching expression failing to compile in Perl and a valid Perl matching expression failing to compile in PCRE. Just because that is the name doesn't make it true.
All three of these representations are capable of describing any regular language (set of symbol sequences, or more intuitively a set of strings), and the fact that a language can be described by an NFA, DFA, or RE implies that it is regular.
I am not hugely familiar with Pearl's "extended regular expression" system, however I was under the understanding that the set of languages it can recognize is a superset of the set of all regular languages. Based on [2], it would appear that Perl regexes can recognize all regular languages, and parts of the set of all Turing-recognizable languages.
0 - Introduction to the Theory of Computation 3/e, Michael Sipser, Thm 1.39, pp. 55.
1 - Introduction to the Theory of Computation 3/e, Michael Sipser, Thm 1.54, pp. 67.
Examples of it look like `$# ($a == $1) { return $$$; }` $# - match any keyword, eg `do`, `while`, etc. $a - match any variable. $1 - match any literal. $$$ - match any block (greedy).
It's also whitespace invariant, so `if($a==$1)` is equivalent to `if ($a == $1)`.
All that to say, I wonder if we're missing out on a variety of "domain specific regexes" for various fields.
I always though that one could make a markup (like markdown) based on regex . Then you could almost directly parse it in any language environment. I'm not sure what the major drawbacks would be though. I guess the expression could get hairy pretty fast as you handle edge cases :)
I'm pretty sure Gruber's original Markdown parser was just regex-based (which is why there are so many weird underspecifications and corner cases). Or do you mean that somehow the document itself is written in a flavor of regex? I'm intrigued but puzzled: what would that even look like?
even though regex isn't quite crossplatform/standardized - it's much more standard than any way of expressing grammars
Of course they have their uses, but I think they should be taken seriously, since sadly, corner cases are hard to weed out of them.