Three of the languages over that we considered in Chapter 2 are:
- , the language of strings ending in ;
- , the language of strings containing either the substring or the substring ; and
- , the language .
Like , both and can be expressed by a formula involving the operations of union, concatenation, and Kleene :
Languages that have formulas like these are called regular languages. In this section we give a recursive definition of the set of regular languages over an alphabet , and later in this chapter we show that these are precisely the languages that can be accepted by a finite automaton.
Definition 3.1Regular Languages over an Alphabet
If is an alphabet, the set of regular languages over is defined as follows.
- The language is an element of , and for every , the language is in .
- For any two languages and in , the three languages
are elements of .
The language is a regular language over , because . If , then can be obtained from the definition by starting with the two languages and and then using the recursive statement in the definition four times: The language is the union ; is the concatenation ; is obtained by applying the Kleene star operation to ; and the final language is the concatenation of and .
A regular language over has an explicit formula. A regular expression for the language is a slightly more user-friendly formula. The only differences are that in a regular expression, parentheses replace and are omitted whenever the rules of precedence allow it, and the union symbol is replaced by . Here are a few examples (see Example 3.5 for a discussion of the last one):
When we write a regular expression like or , which contains neither nor and corresponds to a one-element language, the regular expression looks just like the string it represents. A more general regular expression involving one or both of these operations can't be mistaken for a string; we can think of it as representing the general form of strings in the language. A regular expression describes a regular language, and a regular language can be described by a regular expression.
We say that two regular expressions are equal if the languages they describe are equal. Some regular-expression identities are more obvious than others. The formula
Example 3.2The Language of Strings in with an Odd Number of 's
A string with an odd number of 's has at least one , and the additional 's can be grouped into pairs. There can be arbitrarily many 's before the first , between any two consecutive 's, and after the last . The expression
The expression
is also not correct, because it doesn't allow strings with just one to end with , and the expression
corrects the mistake. Another correct expression is
All of these could also be written with the single on the right, as in
Example 3.3The Language of Strings in Ending with and Not Containing
If a string does not contain the substring , then every in the string either is followed immediately by or is the last symbol in the string. If the string ends with , then every is followed immediately by . Therefore, every string in the language of strings that end with and do not contain matches the regular expression . This regular expression does not describe , however, because it allows the null string, which does not end with . At least one of the two strings and must occur, and so a regular expression for is
Example 3.4Strings in in Which Both the Number of 's and the Number of 's Are Even
One of the regular expressions given in Example 3.2, , describes the language of strings with an odd number of 's, and the final portion of it, , describes the language of strings with an even number of 's. We can interpret the two terms inside the parentheses as representing the two possible ways of adding to the string without changing the parity (the evenness or oddness) of the number of 's: adding a string that has no 's, and adding a string that has two 's. Every string with an even number of 's has a prefix matching one of these two terms, and can be decomposed into nonoverlapping substrings that match one of these terms.
Let be the subset of containing the strings for which both and are even. Every element of has even length. We can use the same approach to find a regular expression for , but this time it's sufficient to consider substrings of even length. The easiest way to add a string of even length without changing the parity of the number of 's or the number of 's is to add or . If a nonnull string does not begin with one of these, then it starts with either or , and the shortest substring following this that restores the evenness of and must also end with or , because its length is even and strings of the form and don't change the parity of or .
The conclusion is that every nonnull string in has a prefix that matches the regular expression
and that a regular expression for is
Example 3.5Regular Expressions and Programming Languages
In Example 2.9 we built a finite automaton to carry out a very simple version of lexical analysis: breaking up a part of a computer program into tokens, which are the basic building blocks from which the expressions or statements are constructed. The last two sections of this chapter are devoted to proving that finite automata can accept exactly the same languages that regular expressions can describe, and in this example we construct regular expressions for two classes of tokens.
An identifier in the C programming language is a string of length 1 or more that contains only letters, digits, and underscores ("") and does not begin with a digit. If we use the abbreviations for "letter," either uppercase or lowercase, and for "digit," then stands for the regular expression
(which has nothing to do with the integer 45), and a regular expression for the language of C identifiers is
Next we look for a regular expression to describe the language of numeric "literals," which typically includes strings such as , , , , , , , , , and . Let us assume that such an expression may or may not begin with a plus sign or a minus sign; it will contain one or more decimal digits, and possibly a decimal point, and it may or may not end with a subexpression starting with . If there is such a subexpression, the portion after may or may not begin with a sign and will contain one or more decimal digits.
Our regular expression will involve the abbreviations and introduced above, and we will use to stand for "sign" (either or a plus sign or a minus sign) and for a decimal point. It is not hard to convince yourself that a regular expression covering all the possibilities is
In some programming languages, numeric literals are not allowed to contain a decimal point unless there is at least one digit on both sides. A regular expression incorporating this requirement is
Other tokens in a high-level language can also be described by regular expressions, in most cases even simpler than the ones in this example. Lexical analysis is the first phase in compiling a high-level-language program. There are programs called lexical-analyzer generators; the input provided to such a program is a set of regular expressions describing the structure of tokens, and the output produced by the program is a software version of an FA that can be incorporated as a token-recognizing module in a compiler. One of the most widely used lexical-analyzer generators is lex, a tool provided in the Unix operating system. It can be used in many situations that require the processing of structured input, but it is often used together with yacc, another Unix tool. The lexical analyzer produced by lex creates a string of tokens; and the parser produced by yacc, on the basis of grammar rules provided as input, is able to determine the syntactic structure of the token string. (yacc stands for yet another compiler compiler.)
Regular expressions come up in Unix in other ways as well. The Unix text editor allows the user to specify a regular expression and searches for patterns in the text that match it. Other commands such as grep (global regular expression print) and egrep (extended global regular expression print) allow a user to search a file for strings that match a specified regular expression.