Regular expression [:digit:] and [[:digit]] difference - regex

I am currently learning regular expression. I met a problem that I can't find answer on stackoverflow and I hope someone can help find the answer.
I use vim in mac OS system and vim shows the line.
If the file "regular_expression.txt" is:
"Open Source" is a good mechanism to develop programs.
You are the No. 1.
Then
grep -n '[:lower:]' regular_expression.txt
will return
1:"Open Source" is a good mechanism to develop programs.
2:You are the No. 1.
The command
grep '[[:lower:]]' regular_expression.txt
will return
2:You are the No. 1.
I can't understand the above difference because it seems to me that [:lower:] is a set of lower characters. [[:lower:]] should be the same as [:lower:]. It is also confusing that in the first case where [:lower:] is used, all the lines in the file are returned.

POSIX character classes must be wrapped in bracket expressions.
The [:lower:] pattern is a positive bracket expression that matches a single char, :, l, o, w, e or r.
The [[:lower:]] pattern is a positive bracket expression that matches any char that is matched with the [:lower:] POSIX character class (that matches any lowercase letters).
See grep manual:
certain named classes of characters are predefined within bracket expressions... Note that the brackets in these class names are part of the symbolic names, and must be included in addition to the brackets delimiting the bracket expression.
If you mistakenly omit the outer brackets, and search for say, [:upper:], GNU grep prints a diagnostic and exits with status 2, on the assumption that you did not intend to search for the nominally equivalent regular expression: [:epru].

Related

Why is POSIX collating-related bracketed symbol higher-precedence than backslash?

POSIX, aka "The Open Group Base Specifications Issue 7, 2018 edition", has this to say about regular expression operator precedence:
9.4.8 ERE Precedence
The order of precedence shall be as shown in the following table:
ERE Precedence (from high to low)
Collation-related bracket symbols
[==] [::] [..]
Escaped characters
\ special-character
Bracket expression
[]
Grouping
()
Single-character-ERE duplication
* + ? {m,n}
Concatenation
ab
Anchoring
^ $
Alternation
|
I am curious as to the reason for the first two levels being in that order. Being a unix user from way back, I am accustomed to being able to "throw a backslash in front of it" to escape virtually anything. But it appears that with Collation-Related-Bracket-Symbols (CRBS), I can't do that. If I want to match a literal [.ch.] I can't just type \[.ch.] and rely on "dot matches dot" to handle things for me. I now have to match something like [[].ch.] (or possibly worse?).
I'm trying, and failing, to imagine what the scenario was when whoever-thought-this-up decided this should be the order. Is there a concrete scenario where having CRBS ranked higher than backslash makes sense, or was this a case of "we don't understand CRBS yet so let's make it higher priority" or ... what, exactly?
At least for Gnu grep, it looks like lib/dfa.c treats the CRBS as one lexical token, as per the function parse_bracket_exp().
For the example given, escaping the special characters (square brackets and dots) seems to give the results you are looking for. You can also match literal dots with [.] which might be easier to see in a regular expression.
$ (echo c;echo '[.ch.]';echo .ch.;echo xchx)|grep '\[\.ch\.\]'
[.ch.]

Is plus (+) part of basic regular expressions?

Recently I was told, that + (one or more occurrence of the previous pattern/character) is not part of basic regex. Not even when written as \+.
It was on a question about maximum compatibility.
I was under the impression that ...
echo "Hello World, I am an example-text" | sed 's#[^a-z0-9]\+#.#ig'
... always results in:
Hello.World.I.am.an.example.text
But then I was told that "it replaces every character not lowercase or a digit followed by + " and that it is the same as [^a-z0-9][+].
So my real question: is there any regex definition or implementation that does not treat either x+ or x\+ the same as xx*.
POSIX "basic" regular expressions do not support + (nor ?!). Most implementations of sed add support for \+ but it's not a POSIX standard feature. If your goal is maximum portability you should avoid using it. Notice that you have to use \+ rather than the more common +.
echo "Hello World, I am an example-text" | sed 's#[^a-z0-9]\+#.#ig'
The -E flag enables "extended" regular expressions, which are a lot closer to the syntax used in Perl, JavaScript, and most other modern regex engines. With -E you don't need to have a backslash; it's simply +.
echo "Hello World, I am an example-text" | sed -E 's#[^a-z0-9]+#.#ig'
From https://www.regular-expressions.info/posix.html:
POSIX or "Portable Operating System Interface for uniX" is a collection of standards that define some of the functionality that a (UNIX) operating system should support. One of these standards defines two flavors of regular expressions. Commands involving regular expressions, such as grep and egrep, implement these flavors on POSIX-compliant UNIX systems. Several database systems also use POSIX regular expressions.
The Basic Regular Expressions or BRE flavor standardizes a flavor similar to the one used by the traditional UNIX grep command. This is pretty much the oldest regular expression flavor still in use today. One thing that sets this flavor apart is that most metacharacters require a backslash to give the metacharacter its flavor. Most other flavors, including POSIX ERE, use a backslash to suppress the meaning of metacharacters. Using a backslash to escape a character that is never a metacharacter is an error.
A BRE supports POSIX bracket expressions, which are similar to character classes in other regex flavors, with a few special features. Shorthands are not supported. Other features using the usual metacharacters are the dot to match any character except a line break, the caret and dollar to match the start and end of the string, and the star to repeat the token zero or more times. To match any of these characters literally, escape them with a backslash.
The other BRE metacharacters require a backslash to give them their special meaning. The reason is that the oldest versions of UNIX grep did not support these. The developers of grep wanted to keep it compatible with existing regular expressions, which may use these characters as literal characters. The BRE a{1,2} matches a{1,2} literally, while a\{1,2\} matches a or aa. Some implementations support \? and \+ as an alternative syntax to \{0,1\} and \{1,\}, but \? and \+ are not part of the POSIX standard. Tokens can be grouped with \( and \). Backreferences are the usual \1 through \9. Only up to 9 groups are permitted. E.g. \(ab\)\1 matches abab, while (ab)\1 is invalid since there's no capturing group corresponding to the backreference \1. Use \\1 to match \1 literally.
POSIX BRE does not support any other features. Even alternation is not supported.
(Emphasis mine.)
So my real question: is there any regex definition or implementation that does not treat either x+ or x\+ the same as xx*.
I can't think of any real world language or tool that supports neither + nor \+.
In the formal mathematical definition of regular expressions there are commonly only three operations defined:
Concatenation: AB matches A followed by B.
Alternation: A|B matches either A or B.
Kleene star: R* matches 0 or more repetitions of R.
These three operations are enough to give the full expressive power of regular expressions†. Operators like ? and + are convenient in programming but not necessary in a mathematical context. If needed, they are defined in terms of the others: R? is R|ε and R+ is RR*.
† Mathematically speaking, that is. Features like back references and lookahead/lookbehind don't exist in formal language theory. Those features add additional expressive power not available in mathematical definitions of regular expressions.
In some traditional sed implementations, you have to enable "extended" regular expressions to get support for + to mean "one or more."
For evidence of this, see: sed plus sign doesn't work

Regex to match all lines not starting with ==

This should be simple, but I've been having trouble with it. I want to write a regex in perl to match all lines that do not begin with an "==". I created this expression:
^[^\=\=].*
Which works fine in a regex tester I use, but when I run the perl script I get an error stating:
POSIX syntax [= =] is reserved for future extensions in regex
And the script terminates. I assume I'm using some syntax wrong, but I haven't found anything regarding this. Does anyone have a better way to match these lines?
Your regex is incorrect, as it fails with =A as input, by example.
A way to do it would be with a Perl Compatible Regular Expression(PCRE): ^(?!==)
You're misunderstanding how character classes work in regular expressions
A character class is delimited by square brackets [...] and generally will match any one of the characters that it encloses. So [abc] will match a, b, or c, but only the first character of aa or cbc. You probably know that you can also use ranges, such as [a-c]
You can also negate the class, as you have done, so [^a] will match any one character that isn't an a, such as z or &, but only the first character of zz
Replicating a character in a class will not change what it matches, so [aardvark] will match exactly one of a, d, k, r, or v, and is equivalent to [adkrv]
Your regex pattern uses the character class [^\=\=]. It's unnecessary to escape an equals sign, and replicating it has no effect, so you have the equivalent of [^=], which will match any single character other than the equals sign =
The reason you got that error message is that character classes beginning [= and ending =] (just [=] doesn't count) are reserved for special behaviour yet to be implemented. As above, there would ordinarily be no reason to write a character class with multiple occurrences of the same character, so it's reasonable to disallow such a construction
perldoc perldiag has this to say
POSIX syntax [= =] is reserved for future extensions in regex; marked by <-- HERE in m/%s/
(F) Within regular expression character classes ([]) the syntax beginning with "[=" and ending with "=]" is reserved for future extensions. If you need to represent those character sequences inside a regular expression character class, just quote the square brackets with the backslash: "[=" and "=]". The <-- HERE shows whereabouts in the regular expression the problem was discovered. See perlre.
A solution depends on how you want to use the test in your Perl code, but if you need an if statement then I would simply invert the test and check that the line doesn't start with ==
unless ( /^==/ )
or, if you're allergic to Perl's unless
if ( not /^==/ )

Grep Pattern matching- underline

I've not been able to find anything online to help so hoping someone may have an idea.
What does an underline in an expression mean when using grep?
For example: [_a-zA-Z0-9]
Could someone help to explain the purpose here?
The grep command uses a regular expression as it is also described in the manpage of grep:
A regular expression is a pattern that describes a set of strings. Regular expressions are constructed analogously to arithmetic expressions, by using various operators to combine smaller expressions.
A quick reference of the regular expression syntax can be found here. To test regular expressions with several input strings I recommend regex101.
The pattern [_a-zA-Z0-9] means to match a single character in the list. The list is opened with [ and closed with ]. The underscore (_) has no special meaning it is literally the underscore character. The minus character (-) means range, here from a to z (a-z) for example.
In short [_a-zA-Z0-9] means to match a single character wich is _, a character of the alphabet either lower or uppercase or a numerical character.

OS X sed -E doesn't accept extended regular expressions

I've been trying various ways to do some basic things with sed on OS X. Here are the results of some simple tests.
echo "foo bar 2011-03-17 17:31:47 foo bar" | sed 's/foo/FOUND/g'
returns (as expected)
FOUND bar 2011-03-17 17:31:47 FOUND bar
but
echo "foo bar 2011-03-17 17:31:47 foo bar" | sed -E 's/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/FOUND/g'
returns
foo bar 2011-03-17 17:31:47 foo bar
and (even more irritatingly)
echo "food bar 2011-03-17 17:31:47 food bar" | sed -E 's/\d/FOUND/g'
returns
fooFOUND bar 2011-03-17 17:31:47 fooFOUND bar
Now, the man sed pages say that
The following options are available:
-E Interpret regular expressions as extended (modern) regular
expressions rather than basic regular expressions (BRE's). The
re_format(7) manual page fully describes both formats.
and man re_format says
\d Matches a digit character. This is equivalent to
`[[:digit:]]'.
And indeed:
echo "foo bar 2011-03-17 17:31:47 foo bar" | sed -E 's/[[:digit:]]{4}/FOUND/g'
gives me
foo bar FOUND-03-17 17:31:47 foo bar
...but this is annoying. Either because I'm being dense, or because the man pages are lying to me (to be honest, I'd prefer the former).
A quick literature review here on SO suggests that I am not alone in this, and that many recommend installing GNU coreutils (or indeed use something else - say perl -pe) -- however, I'd like to be certain:
Do EREs work with sed as it is bundled with OS X -- as implied by the man pages -- or not?
(I'm on 10.8 and 10.6.8)
On macOS, \d is part of a regex feature set called enhanced features - note the distinction in name: enhanced, which is NOT the same as extended.
Instead, enhanced features are a separate dimension from basic vs. extended, which can be activated for both basic and extended regexes. In other words: you can have enhanced basic regexes as well as enhanced extended regexes.
However, it appears that whether enhanced features are available in a given utility is precompiled into it; in other words: a given utility either supports enhanced features or it doesn't - no option can change that.
(Options only allow you to choose between basic and extended, such as -E for sed and grep.)
For a description of all enhanced features, see section ENHANCED FEATURES in man re_format.
It should also be noted that if POSIX compatibility is important, enhanced features should be avoided with sed.
There are POSIX utilities, such as awk, that do support EREs (extended regular expressions), but (a), the POSIX spec explicitly has to state so, and (b) the syntax is limited to POSIX EREs, which are less powerful than the EREs offered by specific platforms.
In practice:
Sadly, the man pages for the various utilities do NOT state whether a given utility supports enhanced regex features, so it comes down to trial and error.
As of macOS 10.15:
macOS sed does NOT support enhanced features, which explains the OP's experience.
E.g., sed -E 's/\d//g' <<<'a10' has no effect, because \d isn't recognized as representing a digit (only [[:digit:]] is).
I have found only one utility that supports enhanced features: grep:
grep -o '\d\+' <<<'a10' # -> '10' - enhanced basic regex
grep -E -o '\d+' <<<'a10' # -> '10' - enhanced extended regex
If you know of others that do, please let us know.
ERE (Extended Regular Expressions) are described in POSIX under (surprise) Regular Expressions or on Mac OS X under man re_format. EREs do not use the PCRE style \d notation to mean digit.
You will need to use either [0-9] or [[:digit:]] to mean digit.
$ echo "foo bar 2011-03-17 17:31:47 foo bar" |
> sed -E 's/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/FOUND/g'
foo bar FOUND foo bar
$ echo "foo bar 2011-03-17 17:31:47 foo bar" |
> sed -E 's/[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}/FOUND/g'
foo bar FOUND foo bar
$
What about \d?
On my Mac OS X (10.7.4), the man re_format does not say anything about \d matching digits.
RE_FORMAT(7) BSD Miscellaneous Information Manual RE_FORMAT(7)
NAME
re_format -- POSIX 1003.2 regular expressions
DESCRIPTION
Regular expressions (``REs''), as defined in IEEE Std 1003.2
(``POSIX.2''), come in two forms: modern REs (roughly those of egrep(1);
1003.2 calls these ``extended'' REs) and obsolete REs (roughly those of
ed(1); 1003.2 ``basic'' REs). Obsolete REs mostly exist for backward
compatibility in some old programs; they will be discussed at the end.
IEEE Std 1003.2 (``POSIX.2'') leaves some aspects of RE syntax and seman-
tics open; `=' marks decisions on these aspects that may not be fully
portable to other IEEE Std 1003.2 (``POSIX.2'') implementations.
A (modern) RE is one= or more non-empty= branches, separated by `|'. It
matches anything that matches one of the branches.
A branch is one= or more pieces, concatenated. It matches a match for
the first, followed by a match for the second, etc.
A piece is an atom possibly followed by a single= `*', `+', `?', or
bound. An atom followed by `*' matches a sequence of 0 or more matches
of the atom. An atom followed by `+' matches a sequence of 1 or more
matches of the atom. An atom followed by `?' matches a sequence of 0 or
1 matches of the atom.
A bound is `{' followed by an unsigned decimal integer, possibly followed
by `,' possibly followed by another unsigned decimal integer, always fol-
lowed by `}'. The integers must lie between 0 and RE_DUP_MAX (255=)
inclusive, and if there are two of them, the first may not exceed the
second. An atom followed by a bound containing one integer i and no
comma matches a sequence of exactly i matches of the atom. An atom fol-
lowed by a bound containing one integer i and a comma matches a sequence
of i or more matches of the atom. An atom followed by a bound containing
two integers i and j matches a sequence of i through j (inclusive)
matches of the atom.
An atom is a regular expression enclosed in `()' (matching a match for
the regular expression), an empty set of `()' (matching the null
string)=, a bracket expression (see below), `.' (matching any single
character), `^' (matching the null string at the beginning of a line),
`$' (matching the null string at the end of a line), a `\' followed by
one of the characters `^.[$()|*+?{\' (matching that character taken as an
ordinary character), a `\' followed by any other character= (matching
that character taken as an ordinary character, as if the `\' had not been
present=), or a single character with no other significance (matching
that character). A `{' followed by a character other than a digit is an
ordinary character, not the beginning of a bound=. It is illegal to end
an RE with `\'.
A bracket expression is a list of characters enclosed in `[]'. It nor-
mally matches any single character from the list (but see below). If the
list begins with `^', it matches any single character (but see below) not
from the rest of the list. If two characters in the list are separated
by `-', this is shorthand for the full range of characters between those
two (inclusive) in the collating sequence, e.g. `[0-9]' in ASCII matches
any decimal digit. It is illegal= for two ranges to share an endpoint,
e.g. `a-c-e'. Ranges are very collating-sequence-dependent, and portable
programs should avoid relying on them.
To include a literal `]' in the list, make it the first character (fol-
lowing a possible `^'). To include a literal `-', make it the first or
last character, or the second endpoint of a range. To use a literal `-'
as the first endpoint of a range, enclose it in `[.' and `.]' to make it
a collating element (see below). With the exception of these and some
combinations using `[' (see next paragraphs), all other special charac-
ters, including `\', lose their special significance within a bracket
expression.
Within a bracket expression, a collating element (a character, a multi-
character sequence that collates as if it were a single character, or a
collating-sequence name for either) enclosed in `[.' and `.]' stands for
the sequence of characters of that collating element. The sequence is a
single element of the bracket expression's list. A bracket expression
containing a multi-character collating element can thus match more than
one character, e.g. if the collating sequence includes a `ch' collating
element, then the RE `[[.ch.]]*c' matches the first five characters of
`chchcc'.
Within a bracket expression, a collating element enclosed in `[=' and
`=]' is an equivalence class, standing for the sequences of characters of
all collating elements equivalent to that one, including itself. (If
there are no other equivalent collating elements, the treatment is as if
the enclosing delimiters were `[.' and `.]'.) For example, if `x' and
`y' are the members of an equivalence class, then `[[=x=]]', `[[=y=]]',
and `[xy]' are all synonymous. An equivalence class may not= be an end-
point of a range.
Within a bracket expression, the name of a character class enclosed in
`[:' and `:]' stands for the list of all characters belonging to that
class. Standard character class names are:
alnum digit punct
alpha graph space
blank lower upper
cntrl print xdigit
These stand for the character classes defined in ctype(3). A locale may
provide others. A character class may not be used as an endpoint of a
range.
A bracketed expression like `[[:class:]]' can be used to match a single
character that belongs to a character class. The reverse, matching any
character that does not belong to a specific class, the negation operator
of bracket expressions may be used: `[^[:class:]]'.
There are two special cases= of bracket expressions: the bracket expres-
sions `[[:<:]]' and `[[:>:]]' match the null string at the beginning and
end of a word respectively. A word is defined as a sequence of word
characters which is neither preceded nor followed by word characters. A
word character is an alnum character (as defined by ctype(3)) or an
underscore. This is an extension, compatible with but not specified by
IEEE Std 1003.2 (``POSIX.2''), and should be used with caution in soft-
ware intended to be portable to other systems.
In the event that an RE could match more than one substring of a given
string, the RE matches the one starting earliest in the string. If the
RE could match more than one substring starting at that point, it matches
the longest. Subexpressions also match the longest possible substrings,
subject to the constraint that the whole match be as long as possible,
with subexpressions starting earlier in the RE taking priority over ones
starting later. Note that higher-level subexpressions thus take priority
over their lower-level component subexpressions.
Match lengths are measured in characters, not collating elements. A null
string is considered longer than no match at all. For example, `bb*'
matches the three middle characters of `abbbc',
`(wee|week)(knights|nights)' matches all ten characters of `weeknights',
when `(.*).*' is matched against `abc' the parenthesized subexpression
matches all three characters, and when `(a*)*' is matched against `bc'
both the whole RE and the parenthesized subexpression match the null
string.
If case-independent matching is specified, the effect is much as if all
case distinctions had vanished from the alphabet. When an alphabetic
that exists in multiple cases appears as an ordinary character outside a
bracket expression, it is effectively transformed into a bracket expres-
sion containing both cases, e.g. `x' becomes `[xX]'. When it appears
inside a bracket expression, all case counterparts of it are added to the
bracket expression, so that (e.g.) `[x]' becomes `[xX]' and `[^x]'
becomes `[^xX]'.
No particular limit is imposed on the length of REs=. Programs intended
to be portable should not employ REs longer than 256 bytes, as an imple-
mentation can refuse to accept such REs and remain POSIX-compliant.
Obsolete (``basic'') regular expressions differ in several respects. `|'
is an ordinary character and there is no equivalent for its functional-
ity. `+' and `?' are ordinary characters, and their functionality can be
expressed using bounds (`{1,}' or `{0,1}' respectively). Also note that
`x+' in modern REs is equivalent to `xx*'. The delimiters for bounds are
`\{' and `\}', with `{' and `}' by themselves ordinary characters. The
parentheses for nested subexpressions are `\(' and `\)', with `(' and `)'
by themselves ordinary characters. `^' is an ordinary character except
at the beginning of the RE or= the beginning of a parenthesized subex-
pression, `$' is an ordinary character except at the end of the RE or=
the end of a parenthesized subexpression, and `*' is an ordinary charac-
ter if it appears at the beginning of the RE or the beginning of a paren-
thesized subexpression (after a possible leading `^'). Finally, there is
one new type of atom, a back reference: `\' followed by a non-zero deci-
mal digit d matches the same sequence of characters matched by the dth
parenthesized subexpression (numbering subexpressions by the positions of
their opening parentheses, left to right), so that (e.g.) `\([bc]\)\1'
matches `bb' or `cc' but not `bc'.
SEE ALSO
regex(3)
Regular Expression Notation, IEEE Std, 1003.2, section 2.8.
BUGS
Having two kinds of REs is a botch.
The current IEEE Std 1003.2 (``POSIX.2'') spec says that `)' is an ordi-
nary character in the absence of an unmatched `('; this was an uninten-
tional result of a wording error, and change is likely. Avoid relying on
it.
Back references are a dreadful botch, posing major problems for efficient
implementations. They are also somewhat vaguely defined (does
`a\(\(b\)*\2\)*d' match `abbbd'?). Avoid using them.
IEEE Std 1003.2 (``POSIX.2'') specification of case-independent matching
is vague. The ``one case implies all cases'' definition given above is
current consensus among implementors as to the right interpretation.
The syntax for word boundaries is incredibly ugly.
BSD March 20, 1994 BSD