1. Why regular expressions

What are regular expressions for?

Regular expressions are used whenever a task requires pattern matching:

  • search engines
  • protein analysis (bioinformatics)
  • search and replace in text editors
  • text processing utilities such as sed and awk

Many programming languages provide various regular expression capabiltiies. Lexical analysers in compilers also use regular expressions.

Finite representation of languages

Consider the following language:

Can we describe this infinite language with a finite pattern?

  • Strings in can start with any number (possibly none) of :

  • Then we have the first , it should be alone and followed by at least one :

  • Then any number (possibly none) of :

  • Then comes the second :

  • Then either:

    • No more but can be any number (possible none) of .
    • Or after some (possibly none) , there is a third somewhere, followed by any number (possibly none) .

    This gives us:

Combining all of these together gives us:

Link to original

2. Examples of regular expressions

Example 2

Given the following language:

We can use the regular expression:

We use the notation: Which we read as “the language of is ”, or “the language represented by is ”.

Example 3

Example 4

Example 5

Find the .

  1. Start by finding

  2. Find

  3. Find We can take any number (possibly none) of words from and concatenate them together.

Example 6

Find the .

  1. Find .
  2. Find .
  3. Find all words starting with or followed by a (possibly empty) word of s.

Example 7

Find the

All the strings that are either empty or start with some (possibly none) s followed by either an , or a followed by (possibly none) s.

For example, .

Link to original

3. Describing regular expressions by recursion

Describing regular expressions by recursion

Regular expression

A regular expression (over alphabet ) is a string consisting of:

  • symbols from
  • and symbols from .
Link to original

The infinite set of regular expression over is defined recursively as follows:

  • Basis case: , , and each symbol in the alphabet are regular expressions.
  • Recursive step: if and are regular expressions, then so are , , and .

Notational conventions

There are some conventions to follow when working with regular expressions:

  • Outermost brackets are omitted.
  • Brackets are omitted when concatenating expressions. e.g. writing instead of .
  • ‘binds’ take precedence over concatenation e.g. we write instead of
Link to original

4. Regular languages

Regular languages

Each regular expression over some alphabet represents a language over $S$.

The following are two different things:

  • A regular expression . A string or finite pattern.
  • The language represents: . A set of words over , words following the pattern.

Regular Language

A regular language is any language that can be representeed by a regular expression. A language is regular if for some regular expression .

Link to original

To compare:

  • A regular expression is a pattern.
  • A regular language is a set of words following a pattern.

Recursive description

The recursive description of the language represented by the regular expression is:

  • Basis Case:
  • Recursive Step: If and are regular expression, then:
    • all words that belong either to or to .
    • any words from followed by any word from
    • any word from followed by any word from … (the number of iterations is arbitrary, possibly none)
Link to original

5-6. Turning regular expressions to NFAs

Turning regular expressions to NFAs

  1. There is a general ‘mechanical’ proecedure that converts any regular expression to an NFA such that . So every regular language is accepted by some automaton.
  2. There is a general ‘mechanical’ procedure that converts any NFA to a regular expression such that . So every language that is accepted by some automaton is regular. This algorithm is out of scope.
title: Regular langauges are <u>precisely those</u> languages that are accepted by finite automata.

Procedure

The procedure which converts any regular expression to an NFA such that operates along the recursive description of the regular expression .

Basis Cases

  • If then .

    digraph {
      rankdir=LR
      init[shape=point]
      node[label="" shape=doublecircle];
      node[shape=circle];
      init->s
    }
  • If then .

    digraph {
      rankdir=LR
      init[shape=point]
      node[label="" shape=doublecircle color=purple] s;
      node[shape=circle];
      init->s
    }
  • If then .

    digraph {
      rankdir=LR
      init[shape=point]
      node[label="" shape=doublecircle color=purple] a;
      node[shape=circle color=""] s;
      init->s
      
      s->a [label=a]
    }

Assumptions for recursive cases

  • : accepts

  • : accepts

    digraph {
      subgraph cluster0 {
      	label="R"
      	init[shape=point]
      	node[label="" shape=doublecircle color=purple] a, b;
      	node[shape=circle color=""] s, c, d;
      	init->s
      }
      
      subgraph cluster1 {
      	label="Z"
      	init2[shape=point]
      	node[label="" shape=doublecircle color=purple] f, g;
      	node[shape=circle color=""] e, h, i;
      	init2->e
      }
    }

Recursive Cases: Automaton accepting (accepted by )

digraph {
	node[label=""]
	
	init[shape=point]
		
	init->z
	z->s [label=ε]
	z->e [label=ε]
 
	subgraph cluster0 {
		label="R"
		node[label="" shape=doublecircle color=purple] a, b;
		node[shape=circle color=""] s, c, d;
	}
 
	subgraph cluster1 {
		label="Z"
		node[label="" shape=doublecircle color=purple] f, g;
		node[shape=circle color=""] e, h, i;
	}
}

Recursive Cases: Automaton accepting (accepted by )

digraph {
  node[label=""]
 
  subgraph cluster1 {
  	label="Z"
  	node[label="" shape=doublecircle color=purple] f, g;
  	node[shape=circle color=""] e, h, i;
  }
  
  subgraph cluster0 {
  	label="R"
  	init[shape=point]
  	node[shape=circle color=""] s, c, d;
  	init->s
  	a->e [label=ε];
  	b->e [label=ε];
  }
}

Recursive Cases: Automaton accepting (accepted by )

digraph {
  init[shape=point];
  	
  node[label="" shape=doublecircle color=purple] w;
  init->w
  
  node[shape=circle color=""]
  w->s
  a->w
  b->w
  	
  subgraph cluster0 {
  	label="R"
  	node[shape=circle color=""] a, b, s, c, d;
  }
}
Link to original

7. Regex to NFA Example 1

Example 1

Apply the proecdure to the regular expression . We construct step-by-step an NFA such that:

Step : automata accepting and

digraph {
	rankdir=LR
	init[shape=point]
	node[label="" shape=doublecircle color=purple] a;
	node[shape=circle color=""] s;
	init->s
 
	s->a [label=a]
}
 
digraph {
	rankdir=LR
	init[shape=point]
	node[label="" shape=doublecircle color=purple] a;
	node[shape=circle color=""] s;
	init->s
 
	s->a [label=b]
}

Step : automata accepting and

digraph {
	rankdir=LR
	init[shape=point]
	node[label="" shape=doublecircle color=purple] b;
	node[shape=circle color=""] s;
	init->s
 
	s->a [label=a]
	a->b [label=b]
}
digraph {
	rankdir=LR
	init[shape=point]
	node[label="" shape=doublecircle color=purple] b;
	node[shape=circle color=""] s;
	init->s
 
	s->a [label=b]
	a->b [label=a]
}

Step : automaton accepting

digraph {
	rankdir=LR
	init[shape=point]
	node[label="" shape=doublecircle color=purple] b,j;
	node[shape=circle color=""] s;
	init->g
 
	s->a [label=a]
	a->b [label=b]
	
	g->s [label=ε]
	g->h [label=ε]
	h->j [label=a]
}

Step : automaton accepting

digraph {
	rankdir=LR
	init[shape=point]
	node[label="" shape=doublecircle color=purple] k;
	node[shape=circle color=""] s;
	init->k
 
	k->g [label=ε]
 
	s->a [label=a]
	a->b [label=b]
	
	g->s [label=ε]
	g->h [label=ε]
	h->j [label=a]
	
	b->k [label=ε]
	j->k [label=ε]
}

Step : automaton accepting

digraph {
	rankdir=LR
	init[shape=point]
	node[label="" shape=doublecircle color=purple] m;
	node[shape=circle color=""] s;
	init->k
 
	k->g [label=ε]
 
	s->a [label=a]
	a->b [label=b]
	
	g->s [label=ε]
	g->h [label=ε]
	h->j [label=a]
	
	b->k [label=ε]
	j->k [label=ε]
	
	k->n [label=b]
	n->m [label=a]
}

Step : automaton accepting

digraph {
	rankdir=LR
	init[shape=point]
	node[label="" shape=doublecircle color=purple] m;
	node[shape=circle color=""] s;
	init->k
 
	k->g [label=ε]
 
	s->a [label=a]
	a->b [label=b]
	
	g->s [label=ε]
	g->h [label=ε]
	h->j [label=a]
	
	b->k [label=ε]
	j->k [label=ε]
	
	k->n [label=b]
	n->m [label=a]
}
Link to original

8. Regex to NFA Example 2

Example 2

Construct an automaton accepting

digraph {
	rankdir=LR
	init[shape=point]
	node[shape=doublecircle]; f;
	node[shape=circle];
	init->a
	
	a->a [label=a]
	a->b [label=ε]
	b->c [label=ε]
	c->d [label=a]
	d->e [label=b]
	e->b [label=ε]
	b->f [label=b]
	f->f [label=b]
	c->g [label=b]
	g->b [label=ε]
}
Link to original

9. Example of nonregular language

Example of nonregular language

Consider the following language over the alphabet :

Suppose that a finite automaton tries to recongise words in this language. Then must store the entire sequence of ‘s before the first shows up. Otherwise will not be able to compare the length of the coming word of s with the length of the prefix of s.

As each automaton is capable for a fixed finite amount of storage with the help of its states, no automaton exists such that .

There is a precise mathematical proof justifying this informal argument: this language is indeed not regular.

Link to original