tr///#
Character-by-character substitution. tr scans a string and replaces every occurrence of a character from SEARCHLIST with the positionally corresponding character from REPLACEMENTLIST, returning the count of characters it touched.
It is not a regex. SEARCHLIST is a set of literal characters (with range shorthand like a-z), not a pattern. No metacharacters, no \d, no variable interpolation. The translation table is built once, at compile time.
Synopsis#
tr/SEARCHLIST/REPLACEMENTLIST/cdsr
y/SEARCHLIST/REPLACEMENTLIST/cdsr
$str =~ tr/abc/xyz/;
$count = ($str =~ tr/aeiou//);
y/// is a sed-compatibility synonym for tr/// - identical behaviour, identical modifiers. See y///.
What you get back#
Without the /r modifier, tr mutates the target string in place and returns the number of characters matched - or, under /d, matched-or-deleted; under /s, matched-before-squashing. The return value is an integer and is commonly used to count characters without changing anything (see the tr/*/*/ idiom below).
With /r, tr leaves the original string alone, builds a transliterated copy, and returns that copy. The returned string is always a plain string - even if the target was a tied variable or a blessed object.
Target without =~: tr operates on $_. Target with =~: the left-hand side must be an lvalue (scalar, array element, hash element) unless /r is used, in which case any expression works.
Modifiers#
The four trailing flags change what tr does with each character it sees. They can be combined:
c- complementSEARCHLIST. The set of characters acted on becomes every character NOT inSEARCHLIST. Under/c,SEARCHLISTis sorted by codepoint after complementing, and anyREPLACEMENTLISTis applied to that sorted set - so the order of characters you wrote inSEARCHLISTno longer matters.d- delete. Characters matched bySEARCHLISTthat have no position inREPLACEMENTLISTare removed from the target entirely rather than replaced with the final replacement character.s- squash. A run of characters that all translate to the same output character collapses to a single instance of that output.r- return modified copy. Do not touch the target. Return the transliterated string instead of a count.
Replacement list length rules#
The relationship between SEARCHLIST and REPLACEMENTLIST changes with the modifiers:
If
REPLACEMENTLISTis shorter thanSEARCHLISTand/dis not in effect, the final replacement character is replicated to fill the gap.tr/abcd/AB/is the same astr/abcd/ABBB/.If
REPLACEMENTLISTis shorter thanSEARCHLISTand/dis in effect, surplusSEARCHLISTcharacters are deleted.tr/abcd/AB/ddoestr/ab/AB/pluss/[cd]//g.If
REPLACEMENTLISTis empty and/dis not in effect,REPLACEMENTLISTbecomes a copy ofSEARCHLIST. This is the count-only form:tr/abc//countsa,b,cwithout changing anything.If
REPLACEMENTLISTis empty and/dis in effect, every character inSEARCHLISTis deleted.tr/abc//dremoves alla,b,cfrom the target.
Character ranges#
A hyphen between two characters specifies an inclusive codepoint range: tr/A-J/0-9/ is tr/ABCDEFGHIJ/0123456789/. A hyphen at the start, at the end, or preceded by a backslash is taken literally - tr/-ab-/xyz/ and tr/\-abc/wxyz/ treat the hyphen as the literal character -.
Only use ASCII-alphabet (same case) or ASCII-digit ranges. a-z, A-Z, 0-9, and clean subsets like h-k or B-E are portable and mean exactly what they read as. Mixed-case ranges, \x-ranges, or ranges straddling the alphabet/digit boundary look obvious but produce different results on non-ASCII platforms - spell them out.
Portable Unicode ranges use \N{U+...} endpoints:
$str =~ tr/\N{U+20}-\N{U+7E}//d; # delete all ASCII printables
Delimiters#
The three delimiters around SEARCHLIST and REPLACEMENTLIST can be any matching pair of printable characters, not just /. Bracketing pairs ({}, (), [], <>) require two independent pairs, one for each list:
tr(aeiouy)(yuoiea);
tr[+\-*/]"ABCD";
When the delimiter is a single quote (tr'...'...'), the lists are treated almost literally - only \\ pairs are collapsed. Hyphens inside single-quoted tr are not range specifiers; they are literal hyphens.
Global state it touches#
Examples#
ASCII lowercase to uppercase:
my $name = "Perl";
$name =~ tr/a-z/A-Z/; # $name is now "PERL"
Count without changing - the tr/X/X/ idiom. The replacement is the same character, so the string is unchanged; the return value is the count:
my $stars = "**hello**";
my $cnt = ($stars =~ tr/*/*/); # $cnt == 4
Empty REPLACEMENTLIST without /d counts, too:
my $digits = ($text =~ tr/0-9//); # count ASCII digits in $text
Delete characters with /d:
my $s = "(555) 123-4567";
$s =~ tr/0-9//cd; # keep only digits: "5551234567"
Squash runs with /s:
my $line = "hello world";
$line =~ tr/ //s; # "hello world"
Non-destructive /r - build a copy, leave the original:
my $host = "example.com";
my $HOST = $host =~ tr/a-z/A-Z/r; # $host unchanged, $HOST uppercased
Chain with other /r operators:
my $tag = $host =~ tr/a-z/A-Z/r
=~ s/\./_/gr; # "EXAMPLE_COM"
map with /r - turn a list of strings into a transformed list:
my @upper = map tr/a-z/A-Z/r, @names;
Whole-word compacting - collapse non-alphabetic runs to a single space:
$sentence =~ tr/a-zA-Z/ /cs; # "foo, bar; BAZ!" -> "foo bar BAZ "
Strip the high bit off every byte:
$bytes =~ tr[\200-\377][\000-\177];
Edge cases#
Not a regex.
tr/\d/X/matches the literal characters\andd, not “any digit”. Character classes, anchors, quantifiers, and backreferences are all silently literal. If you want regex, uses///.No variable interpolation.
$varand@varinside the lists are literal$/@plus the following name. The table is compiled once, when the program is parsed. To build the lists dynamically, wrap ineval:eval "tr/$from/$to/"; die $@ if $@;
Repeated characters in
SEARCHLIST- only the first mapping counts.tr/AAA/XYZ/translates everyAtoX; theYandZpositions are unreachable.No rescan. Transliterated output is not re-fed into the table, even if the replacement character appears in
SEARCHLISTtoo.tr/ox/xo/turns"oxxo"into"xoox", not some fixed point.!~withtr- returns0if any character was changed,1otherwise. Useful only for quick “nothing happened” checks:$foo !~ tr/A/a/ # true iff no 'A' was in $foo
Lvalue requirement. Without
/r, the=~target must be assignable."constant" =~ tr/a/b/is a compile-time error./ralways returns a plain string. If the target is a tied scalar or a blessed string-overloaded object,/rstrips the magic and gives you a fresh plain string.tris not the shelltr(1). Similar syntax, overlapping semantics, but case-folding beyond ASCII belongs tolc/uc/lcfirst/ucfirstor tos///with\U/\L- not totr./cwith a multi-characterREPLACEMENTLISTis non-portable across character sets. Under/cthe search set is sorted by codepoint, and that sort order differs between ASCII and EBCDIC. Stick to single-characterREPLACEMENTLISTwhen combining with/c, or use/conly with/d(where the replacement doesn’t matter).
Differences from upstream#
Fully compatible with upstream Perl 5.44.
See also#
y///- sed-compatibility synonym fortr///; identical behaviour, pick whichever reads better in contexts///- full regex substitution; reach for it when you need patterns, captures, or variable interpolation in the search sidelc- Unicode-aware lowercase; use instead oftr/A-Z/a-z/when the input may contain non-ASCII letterstrinperlop- the upstream reference for the quote-like operator form, delimiter rules, and range portability$_- default target whentris used without=~or!~