こんにちは!今回は、PHPの標準関数であるstrtr()について詳しく解説していきます。文字列の文字を1対1で置換したり、複数のパターンを一度に置換できる、非常に便利な関数です!
strtr関数とは?
strtr()関数は、文字列内の文字を変換・置換する関数です。
“string translate”の略で、2つの使い方があります:
- 文字の1対1変換(文字マッピング)
- 文字列の複数パターン置換(配列置換)
基本的な構文
// 方法1: 文字の1対1変換
strtr(string $string, string $from, string $to): string
// 方法2: 配列による置換
strtr(string $string, array $replace_pairs): string
- $string: 対象の文字列
- $from: 変換元の文字列(方法1)
- $to: 変換先の文字列(方法1)
- $replace_pairs: 置換ペアの連想配列(方法2)
- 戻り値: 変換後の文字列
基本的な使用例
方法1: 文字の1対1変換
// 文字を1対1で置換
$text = "hello";
$result = strtr($text, "helo", "HELO");
echo $result . "\n";
// 出力: HELLO
// 複数の文字を変換
$text = "apple";
$result = strtr($text, "apl", "APL");
echo $result . "\n";
// 出力: APPLe
// 文字の入れ替え
$text = "abc";
$result = strtr($text, "abc", "bca");
echo $result . "\n";
// 出力: bca
方法2: 配列による置換
// 文字列パターンを置換
$text = "Hello World";
$replace = [
'Hello' => 'Hi',
'World' => 'PHP'
];
$result = strtr($text, $replace);
echo $result . "\n";
// 出力: Hi PHP
// 複数パターンの置換
$text = "I like apples and bananas";
$replace = [
'apples' => 'oranges',
'bananas' => 'grapes'
];
$result = strtr($text, $replace);
echo $result . "\n";
// 出力: I like oranges and grapes
長さの違う文字列での動作
// 方法1: 長さが異なる場合、短い方に合わせる
$text = "hello";
$result = strtr($text, "helo", "HELP"); // 最後のPは無視される
echo $result . "\n";
// 出力: HELLO
// 方法2: 長さは関係なく置換
$text = "hello world";
$replace = [
'hello' => 'hi',
'world' => 'universe'
];
$result = strtr($text, $replace);
echo $result . "\n";
// 出力: hi universe
実践的な使用例
例1: ROT13暗号化
class SimpleEncryption {
/**
* ROT13エンコード(strtrを使用)
*/
public static function rot13($text) {
$from = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$to = 'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM';
return strtr($text, $from, $to);
}
/**
* シーザー暗号(シフト数指定)
*/
public static function caesar($text, $shift) {
$alpha = 'abcdefghijklmnopqrstuvwxyz';
$shifted = substr($alpha, $shift) . substr($alpha, 0, $shift);
// 小文字のみ対応
return strtr(strtolower($text), $alpha, $shifted);
}
/**
* 簡易置換暗号
*/
public static function substitution($text, $key) {
$alpha = 'abcdefghijklmnopqrstuvwxyz';
if (strlen($key) !== 26) {
throw new Exception("Key must be 26 characters");
}
return strtr(strtolower($text), $alpha, strtolower($key));
}
/**
* 文字マッピング暗号
*/
public static function mapEncrypt($text) {
$map = [
'a' => '@',
'e' => '3',
'i' => '!',
'o' => '0',
's' => '$',
't' => '7'
];
return strtr(strtolower($text), $map);
}
}
// 使用例
echo "=== ROT13 ===\n";
$text = "Hello World";
$encoded = SimpleEncryption::rot13($text);
echo "元: {$text}\n";
echo "暗号化: {$encoded}\n";
echo "復号化: " . SimpleEncryption::rot13($encoded) . "\n";
echo "\n=== シーザー暗号 ===\n";
$text = "attack at dawn";
$encrypted = SimpleEncryption::caesar($text, 3);
echo "元: {$text}\n";
echo "暗号化: {$encrypted}\n";
echo "\n=== 文字マッピング ===\n";
$text = "secret message";
echo "元: {$text}\n";
echo "暗号化: " . SimpleEncryption::mapEncrypt($text) . "\n";
例2: データのサニタイズと正規化
class DataSanitizer {
/**
* 特殊文字をHTMLエンティティに
*/
public static function escapeHtml($text) {
$replace = [
'<' => '<',
'>' => '>',
'"' => '"',
"'" => ''',
'&' => '&'
];
return strtr($text, $replace);
}
/**
* 全角数字を半角に
*/
public static function normalizeNumbers($text) {
$from = '0123456789';
$to = '0123456789';
return strtr($text, $from, $to);
}
/**
* 全角英字を半角に
*/
public static function normalizeAlpha($text) {
$from = 'abcdefghijklmnopqrstuvwxyz';
$from .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$to = 'abcdefghijklmnopqrstuvwxyz';
$to .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
return strtr($text, $from, $to);
}
/**
* 記号を除去
*/
public static function removeSymbols($text) {
$symbols = '!@#$%^&*()_+-=[]{}|;:,.<>?/~`';
$spaces = str_repeat(' ', strlen($symbols));
return strtr($text, $symbols, $spaces);
}
/**
* スマート引用符を通常の引用符に
*/
public static function normalizeQuotes($text) {
$replace = [
''' => "'",
''' => "'",
'"' => '"',
'"' => '"',
'„' => '"',
'‹' => '<',
'›' => '>'
];
return strtr($text, $replace);
}
}
// 使用例
echo "=== HTMLエスケープ ===\n";
$html = '<script>alert("XSS")</script>';
echo DataSanitizer::escapeHtml($html) . "\n";
echo "\n=== 全角数字正規化 ===\n";
$text = "電話番号:090-1234-5678";
echo DataSanitizer::normalizeNumbers($text) . "\n";
echo "\n=== 全角英字正規化 ===\n";
$text = "HelloWorld";
echo DataSanitizer::normalizeAlpha($text) . "\n";
echo "\n=== スマート引用符正規化 ===\n";
$text = "He said "Hello" and 'Goodbye'";
echo DataSanitizer::normalizeQuotes($text) . "\n";
例3: テンプレート処理
class TemplateEngine {
/**
* 変数を置換
*/
public static function render($template, $variables) {
$replace = [];
foreach ($variables as $key => $value) {
$replace['{' . $key . '}'] = $value;
}
return strtr($template, $replace);
}
/**
* 複数のプレースホルダーを置換
*/
public static function replacePlaceholders($text, $data) {
$replace = [];
foreach ($data as $key => $value) {
$replace['{{' . $key . '}}'] = $value;
$replace['[[' . $key . ']]'] = $value;
$replace['%' . $key . '%'] = $value;
}
return strtr($text, $replace);
}
/**
* メールテンプレート処理
*/
public static function processEmailTemplate($template, $user) {
$replace = [
'{name}' => $user['name'],
'{email}' => $user['email'],
'{date}' => date('Y-m-d'),
'{year}' => date('Y')
];
return strtr($template, $replace);
}
/**
* SQLテンプレート処理
*/
public static function buildQuery($template, $params) {
$replace = [];
foreach ($params as $key => $value) {
if (is_string($value)) {
$value = "'{$value}'";
} elseif (is_null($value)) {
$value = 'NULL';
} elseif (is_bool($value)) {
$value = $value ? '1' : '0';
}
$replace[':' . $key] = $value;
}
return strtr($template, $replace);
}
}
// 使用例
echo "=== テンプレート処理 ===\n";
$template = "Hello {name}, welcome to {site}!";
$vars = [
'name' => 'John',
'site' => 'MyWebsite'
];
echo TemplateEngine::render($template, $vars) . "\n";
echo "\n=== メールテンプレート ===\n";
$emailTemplate = "Dear {name},\n\nYour email is {email}.\n\nDate: {date}";
$user = [
'name' => 'Alice',
'email' => 'alice@example.com'
];
echo TemplateEngine::processEmailTemplate($emailTemplate, $user) . "\n";
echo "\n=== SQLテンプレート ===\n";
$sqlTemplate = "SELECT * FROM users WHERE name = :name AND active = :active";
$params = [
'name' => 'John',
'active' => true
];
echo TemplateEngine::buildQuery($sqlTemplate, $params) . "\n";
例4: URLとパスの処理
class UrlPathTranslator {
/**
* URLエンコード風の文字変換
*/
public static function encodeSpecialChars($url) {
$replace = [
' ' => '%20',
'!' => '%21',
'#' => '%23',
'$' => '%24',
'&' => '%26',
"'" => '%27',
'(' => '%28',
')' => '%29'
];
return strtr($url, $replace);
}
/**
* パス区切り文字を統一
*/
public static function normalizePath($path) {
return strtr($path, '\\', '/');
}
/**
* スラッグを生成
*/
public static function createSlug($text) {
// 特殊文字をハイフンに
$replace = [
' ' => '-',
'_' => '-',
'/' => '-',
'\\' => '-',
'.' => '-'
];
$slug = strtr($text, $replace);
// 小文字に変換
$slug = strtolower($slug);
// 連続するハイフンを1つに
$slug = preg_replace('/-+/', '-', $slug);
return trim($slug, '-');
}
/**
* ファイルパスの変換
*/
public static function convertPathSeparators($path, $separator = '/') {
$replace = [
'/' => $separator,
'\\' => $separator
];
return strtr($path, $replace);
}
}
// 使用例
echo "=== URL特殊文字変換 ===\n";
$url = "example.com/search?q=hello world&sort=date";
echo UrlPathTranslator::encodeSpecialChars($url) . "\n";
echo "\n=== パス正規化 ===\n";
$path = "C:\\Users\\Documents\\file.txt";
echo UrlPathTranslator::normalizePath($path) . "\n";
echo "\n=== スラッグ生成 ===\n";
$titles = [
'Hello World',
'PHP Programming Guide',
'Best_Practices.2024'
];
foreach ($titles as $title) {
echo "{$title} → " . UrlPathTranslator::createSlug($title) . "\n";
}
例5: ファイル名の処理
class FileNameTranslator {
/**
* 安全なファイル名に変換
*/
public static function sanitize($filename) {
// 危険な文字を置換
$replace = [
'<' => '',
'>' => '',
':' => '-',
'"' => '',
'/' => '-',
'\\' => '-',
'|' => '-',
'?' => '',
'*' => '',
' ' => '_'
];
return strtr($filename, $replace);
}
/**
* 日本語ファイル名をローマ字に
*/
public static function romanize($filename) {
$replace = [
'あ' => 'a', 'い' => 'i', 'う' => 'u', 'え' => 'e', 'お' => 'o',
'か' => 'ka', 'き' => 'ki', 'く' => 'ku', 'け' => 'ke', 'こ' => 'ko',
'さ' => 'sa', 'し' => 'shi', 'す' => 'su', 'せ' => 'se', 'そ' => 'so',
// 簡易版(実際はもっと多くの文字が必要)
];
return strtr($filename, $replace);
}
/**
* 大文字を小文字に、スペースをアンダースコアに
*/
public static function normalize($filename) {
$info = pathinfo($filename);
$basename = $info['filename'];
$extension = isset($info['extension']) ? $info['extension'] : '';
// スペースをアンダースコアに
$basename = strtr($basename, ' ', '_');
// 小文字に
$basename = strtolower($basename);
if (!empty($extension)) {
return $basename . '.' . strtolower($extension);
}
return $basename;
}
}
// 使用例
echo "=== ファイル名サニタイズ ===\n";
$unsafeNames = [
'my<file>.txt',
'document:version2.pdf',
'photo|final.jpg',
'test file.doc'
];
foreach ($unsafeNames as $name) {
echo "{$name} → " . FileNameTranslator::sanitize($name) . "\n";
}
echo "\n=== ファイル名正規化 ===\n";
$names = ['My Document.PDF', 'Photo 2024.JPG', 'Test File.TXT'];
foreach ($names as $name) {
echo "{$name} → " . FileNameTranslator::normalize($name) . "\n";
}
例6: テキスト変換
class TextTransformer {
/**
* 数字を単語に
*/
public static function numbersToWords($text) {
$replace = [
'0' => 'zero',
'1' => 'one',
'2' => 'two',
'3' => 'three',
'4' => 'four',
'5' => 'five',
'6' => 'six',
'7' => 'seven',
'8' => 'eight',
'9' => 'nine'
];
return strtr($text, $replace);
}
/**
* リート文字に変換
*/
public static function toLeetSpeak($text) {
$replace = [
'a' => '4',
'e' => '3',
'i' => '1',
'o' => '0',
's' => '5',
't' => '7',
'l' => '1',
'A' => '4',
'E' => '3',
'I' => '1',
'O' => '0',
'S' => '5',
'T' => '7',
'L' => '1'
];
return strtr($text, $replace);
}
/**
* 絵文字テキストに変換
*/
public static function toEmoji($text) {
$replace = [
':)' => '😊',
':(' => '😢',
':D' => '😃',
';)' => '😉',
'<3' => '❤️',
':P' => '😛',
'XD' => '😆'
];
return strtr($text, $replace);
}
/**
* マークダウン風に変換
*/
public static function toMarkdownStyle($text) {
$replace = [
'**' => '<strong>',
'__' => '<em>',
'~~' => '<del>'
];
return strtr($text, $replace);
}
}
// 使用例
echo "=== 数字を単語に ===\n";
$text = "I have 3 apples and 5 oranges";
echo TextTransformer::numbersToWords($text) . "\n";
echo "\n=== リート文字 ===\n";
$text = "Hello World";
echo TextTransformer::toLeetSpeak($text) . "\n";
echo "\n=== 絵文字変換 ===\n";
$text = "I love PHP :) It makes me happy :D";
echo TextTransformer::toEmoji($text) . "\n";
例7: データフォーマット変換
class FormatConverter {
/**
* 日付フォーマット変換
*/
public static function convertDateFormat($date, $fromFormat, $toFormat) {
$replace = [];
// fromFormatからtoFormatへのマッピング
$formatMap = [
'YYYY' => date('Y', strtotime($date)),
'MM' => date('m', strtotime($date)),
'DD' => date('d', strtotime($date))
];
return strtr($toFormat, $formatMap);
}
/**
* 電話番号フォーマット変換
*/
public static function formatPhone($phone, $format = '(###) ###-####') {
// 数字のみ抽出
$numbers = preg_replace('/[^0-9]/', '', $phone);
$result = $format;
for ($i = 0; $i < strlen($numbers); $i++) {
$result = preg_replace('/#/', $numbers[$i], $result, 1);
}
return $result;
}
/**
* クレジットカード番号フォーマット
*/
public static function formatCreditCard($number) {
$clean = preg_replace('/[^0-9]/', '', $number);
// 4桁ごとにスペース
return chunk_split($clean, 4, ' ');
}
}
// 使用例
echo "=== 電話番号フォーマット ===\n";
$phone = "1234567890";
echo FormatConverter::formatPhone($phone) . "\n";
echo FormatConverter::formatPhone($phone, '###-###-####') . "\n";
echo "\n=== クレジットカード番号 ===\n";
$card = "1234567812345678";
echo FormatConverter::formatCreditCard($card) . "\n";
str_replace()との違い
$text = "apple apple";
// str_replace(): すべての出現を順次置換(重複する可能性がある)
$result = str_replace(['apple', 'app'], ['application', 'APP'], $text);
echo "str_replace: {$result}\n";
// applicationlication applicationlication
// strtr(): 最長一致で置換(重複しない)
$result = strtr($text, ['apple' => 'application', 'app' => 'APP']);
echo "strtr: {$result}\n";
// application application
// strtr()は最長一致を優先するため、より予測可能
パフォーマンスの考慮
// 大量の置換処理
$text = str_repeat("abcdefghij", 10000);
$replace = [
'a' => 'A',
'b' => 'B',
'c' => 'C',
'd' => 'D',
'e' => 'E'
];
// strtr()
$start = microtime(true);
for ($i = 0; $i < 100; $i++) {
strtr($text, $replace);
}
$time1 = microtime(true) - $start;
// 複数のstr_replace()
$start = microtime(true);
for ($i = 0; $i < 100; $i++) {
$result = $text;
foreach ($replace as $from => $to) {
$result = str_replace($from, $to, $result);
}
}
$time2 = microtime(true) - $start;
echo "strtr(): {$time1}秒\n";
echo "str_replace()ループ: {$time2}秒\n";
// strtr()は一度に処理するため高速
まとめ
strtr()関数の特徴をまとめると:
できること:
- 文字の1対1変換
- 複数パターンの同時置換
- 最長一致による置換
2つの使用方法:
- 文字変換:
strtr($str, $from, $to)– 文字単位の変換 - 配列置換:
strtr($str, $array)– パターン置換
推奨される使用場面:
- ROT13などの暗号化
- テンプレート処理
- データサニタイズ
- 文字の正規化
- ファイル名の処理
- テキスト変換
str_replace()との違い:
str_replace(): 順次置換、重複の可能性ありstrtr(): 最長一致、重複なし、より予測可能
利点:
- 複数の置換を一度に処理
- 最長一致で安全
- 高速(特に配列置換)
注意点:
- 文字変換では長さが短い方に合わせる
- 配列置換では最長一致を優先
- 元の文字列は変更されない
関連関数:
str_replace(): 文字列置換str_ireplace(): 大文字小文字を区別しない置換preg_replace(): 正規表現による置換
strtr()は、複数の置換パターンを扱う場合に非常に便利で効率的です。最長一致の特性を理解して、適切な場面で活用しましょう!
