Regular Expressions
## Learning Objectives
- Master pattern matching
- Use substitutions and transliterations
- Work with qr// for compiled patterns
- Understand regex modifiers
- Master regex quoting
## Basic Matching
### =~ Operator
```perl
use strict;
use warnings;
my $text = "Hello, World!";
if ($text =~ /World/) {
print "Found!\n";
}
my $found = $text =~ /World/; # 1 or undef
```
### Matching with Variables
```perl
my $pattern = "World";
my $text = "Hello, World!";
if ($text =~ /$pattern/) {
print "Matched!\n";
}
```
### Default Variable $_
```perl
use strict;
use warnings;
$_ = "Hello, World!";
if (/World/) {
print "Found in \$_\n";
}
print "Found" if /World/;
```
## Regex Modifiers
### Common Modifiers
```perl
my $text = "Hello WORLD";
/world/i; # i - Case insensitive
/HELLO/i; # Matches "HELLO", "hello", "Hello", etc.
my $multiline = "line1\nline2\npattern\nline4";
$multiline =~ /^pattern/m; # m - Multiline (^ matches line starts)
my $file_content = "first\nsecond\nthird";
$file_content =~ /\Afirst/; # \A matches absolute start
$file_content =~ /\zthird/; # \z matches absolute end
```
### Extended Modifiers
```perl
my $text = "Comment line\n indented code";
$text =~ /^\s+#\s+(\w+)/x; # x - Extended (allow whitespace and comments)
my $balanced = "((a + b) * c)";
$balanced =~ /\((?:[^()]++|\([^()]*\))+\)/; # + - Possessive (no backtrack)
my $str = "a\nb\nc";
$str =~ /a.*\n.*\n.*/s; # s - Single line (. matches \n)
```
## Character Classes
### Basic Classes
```perl
/[abc]/; # a, b, or c
/[^abc]/; # NOT a, b, or c
/[a-z]/; # lowercase letter
/[A-Z]/; # uppercase letter
/[0-9]/; # digit
/[a-zA-Z0-9]/; # alphanumeric
```
### Shorthand Classes
```perl
/\d/; # Digit [0-9]
/\D/; # Non-digit [^0-9]
/\w/; # Word char [a-zA-Z0-9_]
/\W/; # Non-word char
/\s/; # Whitespace [ \t\n\r\f]
/\S/; # Non-whitespace
```
### Examples
```perl
my $phone = "123-456-7890";
if ($phone =~ /\d{3}-\d{3}-\d{4}/) {
print "Valid phone\n";
}
my $ip = "192.168.1.1";
if ($ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) {
print "Looks like IP\n";
}
```
## Quantifiers
### Basic Quantifiers
```perl
/a*/; # Zero or more a's
/a+/; # One or more a's
/a?/; # Zero or one a
/a{3}/; # Exactly 3 a's
/a{3,}/; # Three or more a's
/a{3,5}/; # Between 3 and 5 a's
```
### Greedy vs Minimal
```perl
my $html = "bold and italic";
$html =~ /<.+>/; # Greedy: matches everything
$html =~ /<.+?>/; # Minimal: matches ... then ...
my $text = "abc123def";
$text =~ /\d+/; # "123" (greedy)
$text =~ /\d+?/; # "1" (minimal)
$text =~ /\d*?/; # "" (zero is minimal match)
```
## Anchors
### Position Anchors
```perl
/^abc/; # Start of string (or line with /m)
/abc$/; # End of string (or line with /m)
/\A/; # Absolute start of string
/\z/; # Absolute end of string
/\b/; # Word boundary
/\B/; # Non-word boundary
```
### Word Boundaries
```perl
my $text = "the them theme";
$text =~ /\bthe\b/; # Matches "the" but not "them" or "theme"
$text =~ /\Bthe\B/; # Matches "the" in "theme" but not standalone
```
## Capturing Groups
### Basic Capturing
```perl
my $date = "2024-01-15";
if ($date =~ /(\d{4})-(\d{2})-(\d{2})/) {
print "Year: $1\n"; # 2024
print "Month: $2\n"; # 01
print "Day: $3\n"; # 15
}
```
### Non-Capturing Groups
```perl
my $text = "abc123def";
# Capturing
if ($text =~ /(\d+)/) {
print "Number: $1\n"; # 123
}
# Non-capturing (?:...)
if ($text =~ /(?:abc)(\d+)/) {
print "Number: $1\n"; # 123 (still $1, abc is not captured)
}
```
### Named Captures
```perl
use 5.010;
my $date = "2024-01-15";
if ($date =~ /(?\d{4})-(?\d{2})-(?\d{2})/) {
print "$+{year}-$+{month}-$+{day}\n";
}
```
## Alternation
### Basic Alternation
```perl
my $color = "blue";
if ($color =~ /red|green|blue/) {
print "Primary color or blue\n";
}
my $extension = "txt";
if ($extension =~ /jpg|png|gif|bmp/) {
print "Image file\n";
}
```
### Precedence
```perl
# | has low precedence
/my (dog|cat)s are (cute|fast)/; # Correct
# vs grouping
/my (dogs|cats) are (cute|fast)/;
```
## Backreferences
### Matching Repeated Characters
```perl
# Match quoted strings (single or double)
my $text = "'hello' and \"world\"";
if ($text =~ /(['"])(.*?)\1/) { # \1 matches same quote
print "Quoted: $2\n";
}
```
### Backreferences in Patterns
```perl
# Match repeated word
my $sentence = "the the cat";
if ($sentence =~ /\b(\w+)\s+\1\b/) {
print "Repeated: $1\n"; # "the"
}
```
## Substitutions
### Basic Substitution
```perl
my $text = "Hello World";
$text =~ s/World/Perl/;
print $text; # "Hello Perl"
# In-place with return value
my $new = $text =~ s/World/Perl/r;
```
### Global Substitution
```perl
my $text = "aaa bbb aaa ccc";
$text =~ s/aaa/bbb/g; # All occurrences
print $text; # "bbb bbb bbb ccc"
# Case-insensitive global
my $words = "Apple apple APPLE";
$words =~ s/apple/fruit/gi; # All, case-insensitive
```
### Multiple Substitutions
```perl
my $text = "hello world";
$text =~ s/hello/hi/r =~ s/world/perl/r =~ s/hi/perl/r;
# Chaining (returns final result)
```
## Transliteration (tr///)
### Basic tr
```perl
my $text = "hello";
$text =~ tr/a-z/A-Z/; # "HELLO"
my $dna = "ACGT";
$dna =~ tr/ACGT/TGCA/; # "TGCA"
```
### tr/// vs s///
```perl
# tr/// - character by character
"abab" =~ s/ab/cd/g; # "cdcd" (substitution)
/ab/ab/cd/g; # "cdcd" (substitution)
/ab/cd/g; # "cdcd" (transliteration)
# s/// - regex substitution
"abab" =~ s/ab+/cd/g; # "cdcd" (replaces 'ab' with 'cd')
```
### Counting with tr
```perl
my $text = "hello world";
my $count = ($text =~ tr/o//); # 2
print "Found $count o's\n";
# Delete
my $clean = $text =~ tr/a-z//cdr; # Remove non-letters
```
## qr// Compiled Patterns
### Basic Usage
```perl
my $pattern = qr/\d{3}-\d{4}/;
if ("123-4567" =~ $pattern) {
print "Match!\n";
}
if ("123-456-7890" =~ $pattern) {
print "Also matches!\n"; # Partial match
}
```
### Combining Patterns
```perl
my $digit = qr/\d+/;
my $hyphen = qr/-/;
my $phone = qr/^$digit$hyphen$digit$/;
"123-456" =~ $phone; # Matches
```
### With Modifiers
```perl
my $case_insensitive = qr/hello/i;
my $multiline = qr/^hello/im;
my $compiled = qr/hello\s+world/ix;
```
## Split with Regex
```perl
my $text = "one,two,three";
my @parts = split /,/, $text; # ("one", "two", "three")
my $date = "2024-01-15";
my ($year, $month, $day) = split /-/, $date;
# With limit
my @words = split /\s+/, "one two three", 2; # ("one", "two three")
# Split on regex
my $line = "abc123def456ghi";
my @nums = split /\D+/, $line; # ("", "123", "456", "ghi")
```
## Global Matches
### Matching All Occurrences
```perl
my $text = "abc123def456";
my @matches = $text =~ /\d+/g;
print "@matches\n"; # "123" "456"
# With capturing
my @all_numbers = $text =~ /(\d+)/g;
print "@all_numbers\n"; # "123" "456"
```
### Iteration
```perl
my $text = "Price: \$100, Discount: \$50";
while ($text =~ /\$\d+/g) {
print "Found: $&\n"; # $& is the matched string
}
# With captures
while ($text =~ /(\$)(\d+)/g) {
print "Currency: $1, Amount: $2\n";
}
```
## Special Variables
```perl
$& # Entire matched string
$` # String before match
$' # String after match
$1 # First capture
$2 # Second capture
$+ # Last capture
$+{name} # Named capture (5.10+)
```
## Lookahead and Lookbehind
### Lookahead
```perl
# Positive lookahead (?=...)
my $text = "foobar";
if ($text =~ /foo(?=bar)/) { } # Match "foo" only if followed by "bar"
# Negative lookahead (?!...)
if ($text =~ /foo(?!bar)/) { } # Match "foo" only if NOT followed by "bar"
```
### Lookbehind
```perl
# Positive lookbehind (?<=...)
my $price = "\$100";
if ($price =~ /(?<=\$)\d+/) { } # Match digits after "$"
# Negative lookbehind (?...)`
- Alternation with `|`
- Substitution: `s/pattern/replacement/g`
- Transliteration: `tr///` for character mapping
- `qr//` compiles patterns for reuse
- Modifiers: `/i`, `/g`, `/m`, `/s`, `/x`
- Global matching with `/g` returns all matches
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →