Regular Expression Pocket Reference 144
Michael J. Ross writes "When software developers need to manipulate text programmatically — such as finding all substrings within some text that match a particular pattern — the most concise and flexible solution is to use "regular expressions," which are strings of characters and symbols that can look anything but regular. Nonetheless, they can be invaluable for locating text that matches a pattern (the "expression"), and optionally replacing the matched text with new text. Regular expressions have proven so popular that they have been incorporated into most if not all major programming languages and editors, and even at least one Web server. But each one implements regular expressions in its own way — which is reason enough for programmers to appreciate the latest edition of Regular Expression Pocket Reference, by Tony Stubblebine." Read below for the rest of Michael's review.
The second edition of the book was published by O'Reilly Media on 18 July 2007, under the ISBNs 0596514271 and 978-0596514273. On the book's Web page, the publisher makes available the book's table of contents and index, as well as links for providing feedback and any errata. As of this writing, there are no unconfirmed errata (those submitted by readers but not yet checked by the author to see whether they are valid), and no confirmed ones, either. In fact, in my review of the first edition, published in 2004, it was noted that there were no unconfirmed errata, despite the book being out for some time prior to that review. The most likely explanation is that the author — in addition to any technical reviewers — did a thorough job of checking all of the regular expressions in the book, along with the sample code that make use of them. These efforts have paid off with the apparent absence of any errors in this new edition — something unseen in any other technical book with which I am familiar.
Regular Expression Pocket Reference, Second Edition | |
author | Tony Stubblebine |
pages | 126 |
publisher | O'Reilly Media |
rating | 9/10 |
reviewer | Michael J. Ross |
ISBN | 0596514271 |
summary | A pithy guide to regular expressions in many languages. |
Before discussing this particular book, it may be of value to briefly discuss the essential concept of regular expressions, for the benefit of any readers who are not familiar with them. As noted earlier, a regular expression (frequently termed a "regex") is a string of characters intended for matching substrings in a block of text. A regex pattern can match literally, such as the pattern "book" matching both "book" and "bookshelf." A pattern can also use special characters and character combinations — often termed metasymbols and metasequences — such as \w to indicate a single word character (A-Z, a-z, 0-9, or '_'). Thus, the regex "b\w\wk" would match "book," but not "brook."
Here is a simple example to show the use of regexes in code, written in Perl: The statement "$text =~ m/book/;" would find the first instance of the string "book" inside the scalar variable $text, which presumably contains some text. To substitute all instances of the string with the word "publication," you could use the statement "$text =~ s/book/publication/g;" ('g' for globally search) or use "$text =~ s/bo{2}k/publication/g;". In this simplistic example, the second statement makes use of a quantifier, {2}, indicating two of the preceding letter.
These examples employ only one metacharacter (\w) and one quantifier ({2}). The total number of metacharacters, metasymbols, quantifiers, character classes, and assertions (to say nothing of capturing, clustering, and alternation) that are available, in most regex-enabled languages, is tremendous. However, the same cannot be said for the readability of all but the simplest regular expressions — especially lengthy ones not improved by whitespace and comments. As a consequence, when using regexes in their code, many programmers find themselves repeatedly consulting reference materials that do not focus on regular expressions. These resources comprise convoluted Perl books, incomplete tutorials on the Internet, and confusing discussions in technical newsgroups. For too many years, there was no published book providing the details of regexes for the various languages that utilize them, in addition to a clear explanation of how to use regexes wisely.
Fortunately, O'Reilly Media offers two titles in hopes of meeting that need: Mastering Regular Expressions, by Jeffrey Friedl, and Regular Expression Pocket Reference, by Tony Stubblebine. In several respects, the books are related — particularly in that Stubblebine bases his slender monograph upon Friedl's larger and more extensive title, justifiably characterized by Stubblebine as "the definitive work on the subject." In addition, Stubblebine's book follows the structure of Friedl's book, and contains page references to the same. Another major difference is that Regular Expression Pocket Reference is, just as the title indicates, for reference purposes only, and not intended as a tutorial.
At first glance, it is clear that Stubblebine's book packs a great deal of information into its modest 126 pages. That may partly be a result of the terseness of most, if not all, of the regular expression syntax; a metasymbol of more than two characters would be considered long-winded! Yet the high information density is likely also due to the manner in which Stubblebine has distilled the operators and rules, as well as the meaning and usage thereof, down to the bare bones. But this does not imply that the book is bereft of examples. Most of the sections contain at least one, and sometimes several, code fragments that illustrate the regex elements under discussion.
The book begins with a brief introduction to regexes and pattern matching, followed by an even briefer cookbook section, with Perl-style regexes for a dozen commonly-needed tasks, e.g., validating dates. The bulk of the book's material is divided into 11 sections, each one devoted to the usage of regexes within a particular language, application, or library: Perl 5.8, Java,.NET and C#, PHP, Python, Ruby, JavaScript, PCRE, the Apache Web server, the vi programmer's editor, and shell tools.
Each of these sections begins with a brief overview of how regexes fit into the overall language covered in that section. Following this is a subsection listing all of the supported metacharacters, with a summary of their meanings, in tabular format. In most cases, this is followed by a subsection showing the usage of those metacharacters — either in the form of operators or pattern-matching functions, depending upon how regular expressions are used within that language. Next is a subsection providing several examples, which is often the first material that most programmers turn to when trying to quickly figure out how to use one aspect of a language. Each section concludes with a short listing of other resources related to regexes for that particular language.
There are no glaring problems in this book, and I can only assume that all of the regular expressions themselves have been tested by the author and by previous readers. However, there is a minor weakness that should be pointed out, and could be corrected in the next edition. In most of the sections' examples, Stubblebine wisely formats the code so that every left brace ("{") is on the same line as the beginning of the statement that uses that brace, and each closing brace ("}") is lined up directly underneath the first character of the statement. This format saves space and makes it easier to match up the statement with its corresponding close brace. However, in the.NET / C# and PCRE library sections, the open braces consume their own lines, and also are indented inconsistently, as are the close braces, which makes the code less readable, as well as less consistent among the sections.
Some readers may fault the book's sparse index. Admittedly, an inadequate index in any sizable programming book can make it difficult if not impossible to find what one is looking for. As a result, one ends up flipping through the book's pages hoping to luckily spot the desired topic. This is the rather unpleasant method to which a reader must resort when a technical book has no index, or one that is inadequate — which is far too often the case. Stubblebine's index offers only several dozen entries for all the letters of the alphabet, and only two symbols. Some readers might demand that all of the metacharacters and metasequences be listed in the index, so they can be found even faster than otherwise. But given the large number of metacharacters and metasequences, as well as method names, module functions, and everything else relevant, creating an exhaustive index would almost double the size of the book, and be largely redundant with the language-specific sections. Within each language, there is typically a limited enough number of pages that scanning through them to find a particular topic, would not be onerous. On the other hand, some of the index's inclusions and omissions are odd. For instance, two symbols are listed, and yet no others; why bother with those two? Also, a few key concepts are missing, such as grouping and capturing.
Yet aside from these minor blemishes, Regular Expression Pocket Reference is a concise, well-written, and information-rich resource that should be kept on hand by any busy software developer.
Michael J. Ross is a Web developer, writer, and freelance editor.
You can purchase Regular Expression Pocket Reference, Second Edition from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
Re: (Score:2)
Re: (Score:2, Informative)
Re: (Score:2)
Re:General introductions to regex? (Score:5, Informative)
http://www.regular-expressions.info/ [regular-expressions.info]
Re: (Score:1)
Re: (Score:3, Funny)
[mini-me:/] luser% grep dead trees
grep: trees: No such file or directory
Re: (Score:2)
Yes you can. You just need quotes, and a lot of patience.
[me@my computer] grep "dead trees"
If you wait long enough, everything you ever wanted will appear.
Re:General introductions to regex? (Score:5, Informative)
http://laurent.riesterer.free.fr/regexp/ [riesterer.free.fr]
It will color code your regex pattern and the associated matches in the string to be searched so you know what is matching what.
Re: (Score:3, Funny)
And for the Mac: RegExhibit (Score:5, Informative)
Here's one for the Mac:
http://homepage.mac.com/roger_jolly/software/index.html#regexhibit [mac.com]
Really? (Score:2)
Mac does not do Tkl/Tc? If it does, the GP post should work on OSX as well.
Neither of these programs look as nice as KDE's Editor [blackie.dk], and that too should work on Mac and Windows soon enough.
Re: (Score:2)
Just a little more modern, KDE Reg Exp Editor (Score:2)
KRegExpEditor [blackie.dk] gives you a nice GUI.
Re: (Score:2, Informative)
Urgh, no. I just had a look at the site, and any site with gems like this right on the front page should definitely be avoided:
Checkin
Re: (Score:2)
'course, it doesn't actually seem to work under Perl 5.8; but I sure as hell ain't trying to debug it
Re: (Score:2)
Re: (Score:2, Insightful)
What's obtuse about them? They're a straightforward and direct way of describing text patterns, and perfectly intuitive if you have an analytical mind (and if you don't, you shouldn't be programming in the first place).
Here's a REXX example from Wikipedia:
T
Re: (Score:2)
Does the book, or any other reference explain why we need such an obtuse mechanism for parsing strings in the first place? Most of the things I read about people doing with regular expressions could be done with much more intuitive string handling methods that have been around since at least the 70s. There may be things that can be done with regex that couldn't be done with (for example) the "parse" statement in Rexx, but it would be a very small percentage of the examples I've seen.
If a person is using a regular expression when they really only direct string parsing, that's the fault of the person, not regular expressions. The annoying details of finite state machines can be ignored if you're just using regular expressions in programming, but if you try to just use conditionals and substrings for all of your text parsing, eventually you'll have a case where you end up essentially writing your own finite state machine.
Re: (Score:2)
I don't think you understand the difference between "possible" and "easy". Using regular expressions to parse text is (really!) easy. Writing a 100% CSS 3, XHTML 1.1 and Javascript 1.7 compliant web browser entirely in x86 assembly by hand (on paper) in 24 hours or less is "possible".
Re: (Score:1, Funny)
Re: (Score:2)
I actually own that book... it talks about fake regular expressions though (ie, not regex).
Re: (Score:1, Informative)
Re: (Score:2)
Re:General introductions to regex? (Score:5, Insightful)
Unless you're a hard core mathhead, that's probably not a good place to start with regexes IMHO. That's just going to scare people off from a highly useful tool. One generally does not need to rigorously prove that his regexes are going to work to use them. One does not have to use every feature of a language to make good use of it.
Re: (Score:2)
Re: (Score:2)
Then you go on and explain wildcards, character classes, and subexpressions and you've covered 95% of what a regular person will use in day to day life, all in the span of about 5 minutes. The hardest part about using regular expressions is usually se
Re: (Score:2)
'course, taking a course in formal language theory is even better (and should be a required course as part of a computing science degree, IMHO).
Re: (Score:2)
Same here.. people here advocating all sorts of wierd stuff like advanced maths theory*, when anyone could work out regular expressions by looking at them for a few minutes. Of course visualisers help for the really complex stuff (which nobody ever uses anyway).
PCRE is actually quite nice - you only have to bother with the setup once. just make a class that you can chuck a regexp string at and reuse it. Depends on the data set I gu
Re: (Score:2)
Re: (Score:2)
Re: (Score:2)
Re: (Score:2)
Actually, that's globbing [wikipedia.org] that the shell does for you, not regex.
Re: (Score:2)
catch 22 (Score:1)
Re: (Score:2)
"Regular Expressions for Onion Routing" (Score:2)
is it better than (Score:2)
Re: (Score:2)
Pair up Google with something like Kodos [sourceforge.net] and you are all set. I still struggle with them sometimes, but nothing like before I had the debugger.
Stand back, everyone (Score:5, Funny)
Re: (Score:2)
Re: (Score:2)
Re: (Score:1, Funny)
Re:Stand back, everyone (Score:5, Funny)
useful regular expression (Score:5, Funny)
"Hello, I'm a smart geeky person, please to not beat me up and take my lunch money. I can help you with your math homework"
Sheldon
Re: (Score:3, Funny)
Now you have math problems.
Re:useful regular expression (Score:4, Informative)
For those of you who don't know the reference:
Some people, when confronted with a problem, think "I know, I'll use regular expressions."
Now they have two problems. --Jamie Zawinski, in comp.lang.emacs
Re: (Score:2)
Re: (Score:1)
Correction for summary (Score:5, Funny)
A minor correction:
However, there is a minor weakness that should be pointed out, and could be corrected in the next edition. Specifically, the book includes a section on
Re: (Score:2)
Re: (Score:2)
ObJWZ (Score:5, Funny)
Because you just can't discuss regular expressions without bringing up this quote [regex.info]:
Some people, when confronted with a problem, think "I know, I'll use regular expressions."
Now they have two problems.
-- Jamie Zawinski, 1997, in alt.religion.emacs
Re: (Score:2)
Re: (Score:2)
Despite being less self-documenting, I have never met a person who prefers to type [[:alnum:]] over \w.
already built in (Score:3, Informative)
There's already a built in regular expression tutorial:
man perlretutRe: (Score:2)
Re: (Score:2)
There's already a built in regular expression tutorial:
man perlretutRe: (Score:2)
Not to be pedantic, but that's neither "built in" nor a "regular expression" tutorial. That's one of the many manpages for Perl that gets installed when you install Perl, and describes, in a friendly format, using Perl and Perl regular expressions.
Which is different than using Perl-compatible regular expressions as described in pcre(3).
Which is different than using Posix regular expressions as described in re_format(7) or grep(1).
So, by a
Why bother with a book? (Score:2)
Opening the Help file for the app and using its search function is a lot quicker than having to leaf through a book (worse when the book has a ba
Problems (Score:3, Interesting)
Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems. --Jamie Zawinski, in comp.lang.emacs
I'll close with a somewhat depressing fact: Regular expression and string processing can be done quickly and efficiently (and was done that way back decades ago, with grep and awk), but is actually done in a horribly inefficient way [swtch.com] in all modern/popular programming language regexp engines.
Re:Problems (Score:5, Interesting)
As for your second complaint... uhh, who cares? Premature optimization is the devil. So if regex's allow you to cleanly implement a simple solution to a problem (and regexes *are* very well suited to certain tasks, even if they do tend to be misused, particularly in languages such as Perl where they're very tightly integrated), it would be foolish to move to another technique based solely on performance concerns without first profiling the code.
'course, the real irony, on the performance front, is that Mr. Zawinski himself said "The heavy use of regexps in Emacs is due almost entirely to performance issues: because of implementation details, Emacs code that uses regexps will almost always run faster than code that uses more traditional control structures." So maybe they aren't so evil or slow after all?
Perl, regexps (Score:3, Interesting)
"Premature optimization" is a nice slogan - but the regexp performance problems are real, and I have encountered them before (I was extremely surprised to see that the regexp matching is scaling far worse than O(N) as it was clear to me that matching that regexp should be at worst O(N)).
The
Re: (Score:3, Interesting)
That's all well and good, but unless you're parsing extremely large volumes of text, the issues are probably unimportant. Which is, of course, why profiling is so important. Throwing out a perfectly valid solution simply because it is, in theory (or even in practice) slow, is ridiculous if you have other performance problems elsewhere, or if the code is running at a speed that is sufficient for the problem at hand.
Put another
Re: (Score:2)
but the regexp performance problems are real, and I have encountered them before
That's all well and good, but unless you're parsing extremely large volumes of text, the issues are probably unimportant. Which is, of course, why profiling is so important. Throwing out a perfectly valid solution simply because it is, in theory (or even in practice) slow, is ridiculous if you have other performance problems elsewhere, or if the code is running at a speed that is sufficient for the problem at hand.
Then again, I'm a linguistics student. And we do quite a bit of work with corpora.
Until now, most of the work has been done in Perl (and some in Intex, Unitex or Nooj); recently some started doing things in C++.
Having read the article above, I think I'll start learning awk. Because we do have major performance issues.
And let me just say: damn. Studying is easy. ;)
If I hope to get a job in hat department, I'll actually have to get something done
Re: (Score:2)
That's all well and good, but unless you're parsing extremely large volumes of text, the issues are probably unimportant.
If you trigger Perl's worst-case regex performance, it can take over a minute to match a 30 character string. That's what the graph at the top of the referenced article illustrates.
/(a?){30}a{30}/'
Try it for yourself:
$ time perl -e '$x= "a" x 30; $x =~
real 3m20.283s
user 3m19.583s
sys 0m0.086s
Will you run into this worst-case performance? Probably not, as long as you write good regexes. Would it behoove you to understand that yes, Perl's regexes can have serious performance issues even with sma
Re: (Score:2)
Then what are they? (Score:2)
Re: (Score:2)
Re: (Score:2)
Premature optimization is the devil.
Wrong. Premature peephole optimization is the devil.
At the design stage choosing a good algorithm that scales is entirely appropriate. This is particularly true when you don't know how much data you'll be working with. Like any scripting language.
Performance criteria are always part of a design and cruddy programmers who hide their incompetence with the above mantra should be fired. See dailywtf [thedailywtf.com] for examples.
---
Don't be a programmer-bureaucrat; someone who su
Re: (Score:2)
Yeah, but when you're talking about 5 milliseconds vs 2 for something that runs once in a blue moon, who gives a fuck?
The problem is that when every programmer does this, and every program is just lots of little operations combined into big ones, then the program as a whole takes seconds to respond instead of milliseconds and likely fails requirements.
Performance is always under consideration, but making it work it approximately infinitely more important.
It is not either-or as you imply. Frequentl
Re: (Score:2)
Bah, I have never once seen a project fail because of software performance issues. A software project is *far* more likely to fail because of poor requirements, poor design, poor management, poor test, or more likely than not, all of the above.
And for those cases where a project *did* fail because of large-scale performance issues, I'd bet dollars to donuts it's because of high-level
Re: (Score:2)
Re: (Score:2)
I'll close with a somewhat depressing fact: Regular expression and string processing can be done quickly and efficiently (and was done that way back decades ago, with grep and awk), but is actually done in a horribly inefficient way [swtch.com] in all modern/popular programming language regexp engines.
I think you'll find that the regex algorithms used in the likes of Perl were chosen for a very good reason - not just because the implementers were lazy or stupid. The author of the article never addresses the fundamental differences in semantics between Posix regular expressions (such as grep and awk implement) and Perl regular expressions semantics. In the Posix case you must find the longest match, a requirement that the Thompson NFA approach handles easily. In the Perl case you must find the first matc
Re: (Score:2)
I'll close with a somewhat depressing fact: Regular expression and string processing can be done quickly and efficiently (and was done that way back decades ago, with grep and awk), but is actually done in a horribly inefficient way [swtch.com] in all modern/popular programming language regexp engines.
That's not true. To get the exponential runtime from your regexps in a pcre-style engine, you have to write some wicked bad regular expressions. In Real Life(tm) backtracking engines are just as good as NFA's. Plus, backreferences are hard to implement using NFA's so you must resort to backtracking them anway. Which is why the authors of Perl's, Python's and PHP:s regular expression libraries have choosen to use recursive backgracking -- it is much simpler and you get the same performance for non-pathologi
Re: (Score:2)
it is much simpler and you get the same performance for non-pathological cases.
Its not that much simpler, as the NFA approach is quite simple. And they indeed speak of the backtracking required in some cases in the article. For backtracking regexps, use this approach, sure. But many (perhaps a majority) of regexps ARE regular and don't need to backtrack.
Claiming that "real world regexps" are not pathological cases may be true - but there is a middle-ground. We have hit, in my workplace, cases of regular expressions scaling much worse than O(N) on the text - and they were completely
Re: (Score:2)
As long as they do it in a backward compatible way I don't care.
Re: (Score:2)
Well it's the job of the language people to do that NFA stuff.
As long as they do it in a backward compatible way I don't care.
They can't. Otherwise they would have. This is the point that the OP seems to have missed - language implementers aren't just a pack of idiots as the OP seems to believe. Non-backtracking NFAs can handle a certain subset of the requirements very efficiently, but can't handle the rest of the requirements at all. Back references are one thing they struggle with. Another is the requirement that many languages (such as Perl) impose to return the first match, not just any match or the longest match.
Re: (Score:2)
The majority of regexps ARE regular and there is no reason for them to pay the price of rare and obscure features that they do not use.
Appearently the regexp implementors are a bunch of idiots after all
Re: (Score:2)
You can fall back to backtracking when the obscure backtracking features are used - and use the regular engine when they are not.
There's nothing obscure about requiring the regex to return the first match. That is simply the semantics that most of these languages have chosen.
Appearently the regexp implementors are a bunch of idiots after all :-)
You seem to prefer to believe that every modern regex implementer is an idiot rather than recognize the fact that the Thompson NFA approach is not suited to the regex semantics most languages now employ. I think that's an extremely arrogant attitude. But hey, if you're so sure you're right then why not produce an implementation that proves it? Perl has pluggabl
Re: (Score:2)
I would take up your challenge, if I wasn't deeply involved with many others already. However, others I have mentioned these problems to have said that they intend to use this as a project.
Re: (Score:2)
Aside: I have noticed that many versions of grep have become extremely slow after they introduced the i18n stuff, so much so that even perl is faster in many common cases.
Switching to the C locale restores performance.
Re: (Score:2)
You got the regexp wrong, take another look at the one in the article, you're missing a ? there.
Also, it may work very quickly with the constant 29, and take years with the constant 35 or 40, such are the wonders of exponential complexities.
Bad index (Score:1)
Regular Expressions & Literate Programming (Score:2)
Re: (Score:2)
I have to get one of these (Score:3, Insightful)
I'd rather stick knitting needles in my eyes than debug a regular expression.
The only cure for that is getting a good reference and having a go at some tutorials until you get good enough to slay the beast. Then you'll be everyone's buddy at the office, because a lot of people feel the same way.
Or you could just stick knitting needles in your eyes and slash your face with a razor and then everyone will leave you alone.
Re: (Score:2)
I'd rather stick knitting needles in my eyes than debug a regular expression.
The only cure for that is getting a good reference and having a go at some tutorials until you get good enough to slay the beast. Then you'll be everyone's buddy at the office, because a lot of people feel the same way.
It's not all that hard if you format them properly with /x first. [perl.com]
:)
If you're using Perl anyway, dunno if others have that feature too. I don't need anything but Perl
Re: (Score:2)
Why do you say that? [ex-parrot.com]
Re: (Score:2, Interesting)
A unanswered question (Score:2)
1) "regh-ex" (hard 'g', like 'ghost')
2) "rej-ex" (soft 'g', like 'gerbil')
3) "re-gex" (hard 'g')
4) "re-jex" (soft 'g')
I use the first one, since those are the two initial syllables of 'regular' and 'expression', but I can see arguments for the others.
Re: (Score:2)
#2 - I don't think of it as the combination of two words, which is probably why I ignore the hard G from 'regular' and replace it with the soft G from 'register'. I do the same with Linux (lin ucks), char (chair), etc.
Although I admit I can't pronounce the word "debacle" correctly for the life of me.
Don't fear - Just download txt2regex (Score:4, Informative)
Therefore I think the best way to learn regular expressions is by example. I highly recommend this small interactive program which will walk you through building regular expressions for a few different languagues. When you think you need a regex for a program, just fire it up and answer the questions.
http://txt2regex.sourceforge.net/ [sourceforge.net]
After a while you won't need txt2regex for simple stuff because you will have hopefully just absorbed the syntax. Once you have mastered the basic regexes which txt2regex can generate you will be able to dive into more advanced topics like capturing groups.
Missing applications (Score:2)
What is the concept of a regular expression? (Score:3, Informative)
A regular expression can be thought of as a program which generates a set of strings - or recognizes a set of strings, which is the same thing. Regular expressions correspond to finite state automatons, so just as a FSA cannot recognize the set of all palindromes, neither can a regular expression. Also languages like perl have extended the capabilities of their regular expression string matchers to include things like backreferences, which cannot be done in a true regular expression, so we tend to use the word 'regexp' nowadays.
Or perhaps I'm just playing the grumpy computer scientist here.
Re: (Score:2)
Re: (Score:3, Informative)
Re: (Score:2)
I think the GP is referring to the kind of regular expressions you'd cover in a finite automata course (which I tend to refer to as "fake regular expressions", since I learned regex first...), not anything you'd actually ever implement in a library or programming language.
Bad example (Score:2)
$text =~ s/book/publication/g;
Yeah, that will work. Not.
Instead of buying the book.. (Score:2)
It is the best $40 I ever spent when doing a project involving tons of Regular Expressions. It has detailed tutorials on how Regular Expressions work, a reference guide, debugging mode, real-time feedback on what your expression is doing, error checking, and a built-in forum where you can post your problems and people including the developer himself will chime in and help you figure it out!
I'm not associated with JGSoft in anyway, but RegEx Buddy really is an awe
Very useful reference (Score:2)