[PHP]strtr関数を完全解説!文字列を置換・変換する方法

PHP

こんにちは!今回は、PHPの標準関数であるstrtr()について詳しく解説していきます。文字列の文字を1対1で置換したり、複数のパターンを一度に置換できる、非常に便利な関数です!

strtr関数とは?

strtr()関数は、文字列内の文字を変換・置換する関数です。

“string translate”の略で、2つの使い方があります:

  1. 文字の1対1変換(文字マッピング)
  2. 文字列の複数パターン置換(配列置換)

基本的な構文

// 方法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 = [
            '<' => '&lt;',
            '>' => '&gt;',
            '"' => '&quot;',
            "'" => '&#039;',
            '&' => '&amp;'
        ];
        
        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つの使用方法:

  1. 文字変換: strtr($str, $from, $to) – 文字単位の変換
  2. 配列置換: strtr($str, $array) – パターン置換

推奨される使用場面:

  • ROT13などの暗号化
  • テンプレート処理
  • データサニタイズ
  • 文字の正規化
  • ファイル名の処理
  • テキスト変換

str_replace()との違い:

  • str_replace(): 順次置換、重複の可能性あり
  • strtr(): 最長一致、重複なし、より予測可能

利点:

  • 複数の置換を一度に処理
  • 最長一致で安全
  • 高速(特に配列置換)

注意点:

  • 文字変換では長さが短い方に合わせる
  • 配列置換では最長一致を優先
  • 元の文字列は変更されない

関連関数:

  • str_replace(): 文字列置換
  • str_ireplace(): 大文字小文字を区別しない置換
  • preg_replace(): 正規表現による置換

strtr()は、複数の置換パターンを扱う場合に非常に便利で効率的です。最長一致の特性を理解して、適切な場面で活用しましょう!

タイトルとURLをコピーしました