[PHP]strtolower関数を完全解説!文字列を小文字に変換する方法

PHP

こんにちは!今回は、PHPの標準関数であるstrtolower()について詳しく解説していきます。文字列をすべて小文字に変換する、シンプルだけど非常によく使われる関数です!

strtolower関数とは?

strtolower()関数は、文字列内のすべての英字を小文字に変換する関数です。

“string to lower”の略で、大文字小文字を統一したい場面や、比較処理、データの正規化など、様々な用途で使用されます!

基本的な構文

strtolower(string $string): string
  • $string: 小文字に変換する文字列
  • 戻り値: 小文字に変換された文字列

基本的な使用例

シンプルな変換

// 大文字を小文字に
$text = "HELLO WORLD";
echo strtolower($text) . "\n";
// 出力: hello world

// 混在した文字列
$text = "Hello World";
echo strtolower($text) . "\n";
// 出力: hello world

// すでに小文字の場合
$text = "hello";
echo strtolower($text) . "\n";
// 出力: hello(変化なし)

数字と記号

// 数字と記号は変化しない
$text = "ABC123!@#";
echo strtolower($text) . "\n";
// 出力: abc123!@#

$text = "Test-Case_2024";
echo strtolower($text) . "\n";
// 出力: test-case_2024

マルチバイト文字の扱い

// ASCII文字のみ処理される
$text = "Hello こんにちは WORLD";
echo strtolower($text) . "\n";
// 出力: hello こんにちは world

// 日本語は変化しない
$text = "テスト TEST テスト";
echo strtolower($text) . "\n";
// 出力: テスト test テスト

// マルチバイト対応が必要な場合
$text = "HELLO";
echo mb_strtolower($text, 'UTF-8') . "\n";
// 出力: hello

実践的な使用例

例1: 大文字小文字を区別しない比較

class CaseInsensitiveComparator {
    /**
     * 大文字小文字を区別しない比較
     */
    public static function equals($str1, $str2) {
        return strtolower($str1) === strtolower($str2);
    }
    
    /**
     * 配列内に含まれるかチェック
     */
    public static function inArray($needle, $haystack) {
        $needle = strtolower($needle);
        
        foreach ($haystack as $item) {
            if (strtolower($item) === $needle) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 配列から検索
     */
    public static function search($needle, $haystack) {
        $needle = strtolower($needle);
        
        foreach ($haystack as $key => $value) {
            if (strtolower($value) === $needle) {
                return $key;
            }
        }
        
        return false;
    }
    
    /**
     * ソート(大文字小文字無視)
     */
    public static function sort($array) {
        usort($array, function($a, $b) {
            return strcmp(strtolower($a), strtolower($b));
        });
        
        return $array;
    }
    
    /**
     * 重複を除去(大文字小文字無視)
     */
    public static function unique($array) {
        $lowercaseMap = [];
        $result = [];
        
        foreach ($array as $item) {
            $lower = strtolower($item);
            
            if (!isset($lowercaseMap[$lower])) {
                $lowercaseMap[$lower] = true;
                $result[] = $item;
            }
        }
        
        return $result;
    }
}

// 使用例
echo "=== 大文字小文字無視比較 ===\n";
var_dump(CaseInsensitiveComparator::equals("Hello", "HELLO"));  // true
var_dump(CaseInsensitiveComparator::equals("Hello", "World"));  // false

$array = ['Apple', 'Banana', 'CHERRY'];
echo "\n=== 配列内検索 ===\n";
var_dump(CaseInsensitiveComparator::inArray('apple', $array));   // true
var_dump(CaseInsensitiveComparator::inArray('BANANA', $array));  // true

echo "\n=== ソート ===\n";
$items = ['Zebra', 'apple', 'BANANA', 'cherry'];
$sorted = CaseInsensitiveComparator::sort($items);
print_r($sorted);

echo "\n=== 重複除去 ===\n";
$items = ['Apple', 'APPLE', 'apple', 'Banana', 'BANANA'];
$unique = CaseInsensitiveComparator::unique($items);
print_r($unique);

例2: URLとスラッグの生成

class SlugGenerator {
    /**
     * URLフレンドリーなスラッグを生成
     */
    public static function generate($text) {
        // 小文字に変換
        $slug = strtolower($text);
        
        // スペースをハイフンに
        $slug = str_replace(' ', '-', $slug);
        
        // 英数字とハイフン以外を除去
        $slug = preg_replace('/[^a-z0-9-]/', '', $slug);
        
        // 連続するハイフンを1つに
        $slug = preg_replace('/-+/', '-', $slug);
        
        // 前後のハイフンを除去
        $slug = trim($slug, '-');
        
        return $slug;
    }
    
    /**
     * タイトルからスラッグを生成
     */
    public static function fromTitle($title) {
        return self::generate($title);
    }
    
    /**
     * ファイル名を正規化
     */
    public static function normalizeFilename($filename) {
        $info = pathinfo($filename);
        $basename = $info['filename'];
        $extension = isset($info['extension']) ? $info['extension'] : '';
        
        $slug = self::generate($basename);
        
        if (!empty($extension)) {
            $slug .= '.' . strtolower($extension);
        }
        
        return $slug;
    }
    
    /**
     * ユニークなスラッグを生成
     */
    public static function generateUnique($text, $existingSlugs) {
        $baseSlug = self::generate($text);
        $slug = $baseSlug;
        $counter = 1;
        
        while (in_array($slug, $existingSlugs)) {
            $slug = $baseSlug . '-' . $counter;
            $counter++;
        }
        
        return $slug;
    }
}

// 使用例
$titles = [
    'Hello World!',
    'PHP Programming Guide',
    'Best Practices 2024',
    'Test@#$%File'
];

echo "=== スラッグ生成 ===\n";
foreach ($titles as $title) {
    echo "{$title} → " . SlugGenerator::generate($title) . "\n";
}

echo "\n=== ファイル名正規化 ===\n";
$files = ['My Document.PDF', 'Photo_2024.JPG', 'test FILE.txt'];
foreach ($files as $file) {
    echo "{$file} → " . SlugGenerator::normalizeFilename($file) . "\n";
}

echo "\n=== ユニークスラッグ ===\n";
$existing = ['hello-world', 'hello-world-1'];
$newSlug = SlugGenerator::generateUnique('Hello World', $existing);
echo $newSlug . "\n";  // hello-world-2

例3: データの正規化

class DataNormalizer {
    /**
     * メールアドレスを正規化
     */
    public static function normalizeEmail($email) {
        return strtolower(trim($email));
    }
    
    /**
     * ユーザー名を正規化
     */
    public static function normalizeUsername($username) {
        return strtolower(trim($username));
    }
    
    /**
     * タグを正規化
     */
    public static function normalizeTags($tags) {
        $normalized = [];
        
        foreach ($tags as $tag) {
            $tag = strtolower(trim($tag));
            
            if (!empty($tag) && !in_array($tag, $normalized)) {
                $normalized[] = $tag;
            }
        }
        
        return $normalized;
    }
    
    /**
     * ドメイン名を正規化
     */
    public static function normalizeDomain($domain) {
        $domain = strtolower(trim($domain));
        
        // プロトコルを除去
        $domain = preg_replace('#^https?://#', '', $domain);
        
        // www. を除去
        $domain = preg_replace('#^www\.#', '', $domain);
        
        // 末尾のスラッシュを除去
        $domain = rtrim($domain, '/');
        
        return $domain;
    }
    
    /**
     * ファイル拡張子を正規化
     */
    public static function normalizeExtension($extension) {
        return strtolower(trim($extension, '.'));
    }
}

// 使用例
echo "=== メールアドレス正規化 ===\n";
$emails = ['User@Example.COM', '  ADMIN@TEST.ORG  ', 'Info@Company.Co.JP'];
foreach ($emails as $email) {
    echo "{$email} → " . DataNormalizer::normalizeEmail($email) . "\n";
}

echo "\n=== タグ正規化 ===\n";
$tags = ['PHP', 'php', 'Programming', 'PROGRAMMING', 'Web'];
$normalized = DataNormalizer::normalizeTags($tags);
print_r($normalized);

echo "\n=== ドメイン正規化 ===\n";
$domains = ['HTTPS://WWW.Example.COM/', 'www.test.org', 'Company.CO.JP'];
foreach ($domains as $domain) {
    echo "{$domain} → " . DataNormalizer::normalizeDomain($domain) . "\n";
}

例4: 検索機能

class SearchEngine {
    /**
     * キーワード検索
     */
    public static function search($text, $keyword) {
        return stripos($text, $keyword) !== false;
        // または: strpos(strtolower($text), strtolower($keyword)) !== false
    }
    
    /**
     * 複数キーワードで検索(AND)
     */
    public static function searchAll($text, $keywords) {
        $lowerText = strtolower($text);
        
        foreach ($keywords as $keyword) {
            if (strpos($lowerText, strtolower($keyword)) === false) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 複数キーワードで検索(OR)
     */
    public static function searchAny($text, $keywords) {
        $lowerText = strtolower($text);
        
        foreach ($keywords as $keyword) {
            if (strpos($lowerText, strtolower($keyword)) !== false) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 配列をフィルタリング
     */
    public static function filter($items, $keyword) {
        $keyword = strtolower($keyword);
        
        return array_filter($items, function($item) use ($keyword) {
            return strpos(strtolower($item), $keyword) !== false;
        });
    }
    
    /**
     * キーワードをハイライト
     */
    public static function highlight($text, $keyword, $tag = 'mark') {
        $lowerText = strtolower($text);
        $lowerKeyword = strtolower($keyword);
        $keywordLength = strlen($keyword);
        
        $result = '';
        $offset = 0;
        
        while (($pos = strpos($lowerText, $lowerKeyword, $offset)) !== false) {
            // マッチ前の部分
            $result .= substr($text, $offset, $pos - $offset);
            
            // ハイライトされたキーワード(元の大文字小文字を保持)
            $result .= "<{$tag}>" . substr($text, $pos, $keywordLength) . "</{$tag}>";
            
            $offset = $pos + $keywordLength;
        }
        
        // 残りの部分
        $result .= substr($text, $offset);
        
        return $result;
    }
}

// 使用例
$text = "PHP is a popular programming language. Many developers love PHP.";

echo "=== 検索 ===\n";
var_dump(SearchEngine::search($text, 'php'));         // true
var_dump(SearchEngine::search($text, 'PHP'));         // true
var_dump(SearchEngine::search($text, 'python'));      // false

echo "\n=== AND検索 ===\n";
var_dump(SearchEngine::searchAll($text, ['PHP', 'programming']));  // true
var_dump(SearchEngine::searchAll($text, ['PHP', 'python']));       // false

echo "\n=== OR検索 ===\n";
var_dump(SearchEngine::searchAny($text, ['python', 'ruby', 'php']));  // true

$items = ['Apple', 'Banana', 'CHERRY', 'date', 'Elderberry'];
echo "\n=== フィルタリング ===\n";
$filtered = SearchEngine::filter($items, 'a');
print_r($filtered);  // Apple, Banana, date

echo "\n=== ハイライト ===\n";
echo SearchEngine::highlight($text, 'php') . "\n";

例5: ファイル処理

class FileProcessor {
    /**
     * 拡張子で分類
     */
    public static function groupByExtension($files) {
        $grouped = [];
        
        foreach ($files as $file) {
            $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
            
            if (!isset($grouped[$ext])) {
                $grouped[$ext] = [];
            }
            
            $grouped[$ext][] = $file;
        }
        
        return $grouped;
    }
    
    /**
     * 特定の拡張子か判定
     */
    public static function hasExtension($filename, $extensions) {
        $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        
        $extensions = array_map('strtolower', $extensions);
        
        return in_array($ext, $extensions);
    }
    
    /**
     * 画像ファイルか判定
     */
    public static function isImage($filename) {
        return self::hasExtension($filename, ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']);
    }
    
    /**
     * ドキュメントファイルか判定
     */
    public static function isDocument($filename) {
        return self::hasExtension($filename, ['pdf', 'doc', 'docx', 'txt', 'rtf']);
    }
    
    /**
     * ファイル名を安全に
     */
    public static function sanitizeFilename($filename) {
        $info = pathinfo($filename);
        $basename = $info['filename'];
        $extension = isset($info['extension']) ? $info['extension'] : '';
        
        // 小文字に変換
        $basename = strtolower($basename);
        
        // 安全な文字のみに
        $basename = preg_replace('/[^a-z0-9-_]/', '-', $basename);
        
        if (!empty($extension)) {
            $basename .= '.' . strtolower($extension);
        }
        
        return $basename;
    }
}

// 使用例
$files = [
    'photo.JPG',
    'document.PDF',
    'image.PNG',
    'report.DOCX',
    'video.MP4'
];

echo "=== 拡張子で分類 ===\n";
$grouped = FileProcessor::groupByExtension($files);
print_r($grouped);

echo "\n=== ファイルタイプ判定 ===\n";
foreach ($files as $file) {
    echo "{$file}: ";
    
    if (FileProcessor::isImage($file)) {
        echo "画像";
    } elseif (FileProcessor::isDocument($file)) {
        echo "ドキュメント";
    } else {
        echo "その他";
    }
    
    echo "\n";
}

echo "\n=== ファイル名サニタイズ ===\n";
$unsafeFiles = ['My Photo.JPG', 'Test@File!.PDF', 'Document (1).DOCX'];
foreach ($unsafeFiles as $file) {
    echo "{$file} → " . FileProcessor::sanitizeFilename($file) . "\n";
}

例6: バリデーション

class Validator {
    /**
     * メールアドレスのドメインをチェック
     */
    public static function isEmailDomain($email, $allowedDomains) {
        $email = strtolower($email);
        $allowedDomains = array_map('strtolower', $allowedDomains);
        
        foreach ($allowedDomains as $domain) {
            if (strpos($email, '@' . $domain) !== false) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 禁止ワードチェック
     */
    public static function containsBannedWords($text, $bannedWords) {
        $lowerText = strtolower($text);
        $bannedWords = array_map('strtolower', $bannedWords);
        
        foreach ($bannedWords as $word) {
            if (strpos($lowerText, $word) !== false) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * ユーザー名が許可されているかチェック
     */
    public static function isValidUsername($username, $reservedNames) {
        $username = strtolower($username);
        $reservedNames = array_map('strtolower', $reservedNames);
        
        return !in_array($username, $reservedNames);
    }
    
    /**
     * ファイル拡張子が許可されているかチェック
     */
    public static function isAllowedFileType($filename, $allowedExtensions) {
        $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        $allowedExtensions = array_map('strtolower', $allowedExtensions);
        
        return in_array($ext, $allowedExtensions);
    }
}

// 使用例
echo "=== メールドメインチェック ===\n";
$allowedDomains = ['example.com', 'company.co.jp'];
var_dump(Validator::isEmailDomain('user@EXAMPLE.COM', $allowedDomains));  // true
var_dump(Validator::isEmailDomain('user@test.org', $allowedDomains));     // false

echo "\n=== 禁止ワードチェック ===\n";
$bannedWords = ['spam', 'viagra', 'casino'];
var_dump(Validator::containsBannedWords('This is SPAM message', $bannedWords));  // true
var_dump(Validator::containsBannedWords('Hello world', $bannedWords));           // false

echo "\n=== 予約ユーザー名チェック ===\n";
$reserved = ['admin', 'root', 'system'];
var_dump(Validator::isValidUsername('ADMIN', $reserved));  // false
var_dump(Validator::isValidUsername('john', $reserved));   // true

echo "\n=== ファイルタイプチェック ===\n";
$allowed = ['jpg', 'png', 'pdf'];
var_dump(Validator::isAllowedFileType('photo.JPG', $allowed));   // true
var_dump(Validator::isAllowedFileType('script.PHP', $allowed));  // false

例7: キャッシュキーの生成

class CacheKeyGenerator {
    /**
     * キャッシュキーを生成
     */
    public static function generate($prefix, $params) {
        // パラメータを正規化
        $normalized = [];
        
        foreach ($params as $key => $value) {
            $key = strtolower($key);
            
            if (is_string($value)) {
                $value = strtolower($value);
            }
            
            $normalized[$key] = $value;
        }
        
        // ソート
        ksort($normalized);
        
        // キー生成
        $key = $prefix . ':' . md5(serialize($normalized));
        
        return strtolower($key);
    }
    
    /**
     * URLからキャッシュキーを生成
     */
    public static function fromUrl($url) {
        $url = strtolower($url);
        $url = preg_replace('#^https?://#', '', $url);
        
        return 'url:' . md5($url);
    }
    
    /**
     * クエリパラメータからキーを生成
     */
    public static function fromQuery($params) {
        $normalized = [];
        
        foreach ($params as $key => $value) {
            $normalized[strtolower($key)] = strtolower($value);
        }
        
        ksort($normalized);
        
        return 'query:' . md5(http_build_query($normalized));
    }
}

// 使用例
echo "=== キャッシュキー生成 ===\n";

$params = ['UserId' => '123', 'Category' => 'ELECTRONICS', 'Sort' => 'PRICE'];
$key = CacheKeyGenerator::generate('product', $params);
echo "パラメータキー: {$key}\n";

$url = 'HTTPS://EXAMPLE.COM/Products?id=123';
$urlKey = CacheKeyGenerator::fromUrl($url);
echo "URLキー: {$urlKey}\n";

$query = ['Page' => '1', 'Limit' => '20', 'Order' => 'ASC'];
$queryKey = CacheKeyGenerator::fromQuery($query);
echo "クエリキー: {$queryKey}\n";

strtoupper()との関係

$text = "Hello World";

// strtolower(): 小文字に変換
echo strtolower($text) . "\n";  // hello world

// strtoupper(): 大文字に変換
echo strtoupper($text) . "\n";  // HELLO WORLD

// 往復変換
$lower = strtolower($text);
$upper = strtoupper($lower);
echo $upper . "\n";  // HELLO WORLD

パフォーマンスの考慮

// 大量のデータで小文字変換
$text = str_repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10000);

// strtolower()
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
    strtolower($text);
}
$time1 = microtime(true) - $start;

// 手動変換
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
    $result = '';
    for ($j = 0; $j < strlen($text); $j++) {
        $char = $text[$j];
        if ($char >= 'A' && $char <= 'Z') {
            $result .= chr(ord($char) + 32);
        } else {
            $result .= $char;
        }
    }
}
$time2 = microtime(true) - $start;

echo "strtolower(): {$time1}秒\n";
echo "手動変換: {$time2}秒\n";

// strtolower()は高度に最適化されており非常に高速

まとめ

strtolower()関数の特徴をまとめると:

できること:

  • 文字列を小文字に変換
  • 大文字小文字を統一
  • 正規化処理

推奨される使用場面:

  • 大文字小文字を区別しない比較
  • データの正規化
  • URL・スラッグの生成
  • 検索機能
  • ファイル処理
  • キャッシュキー生成

注意点:

  • ASCII文字のみ処理(A-Z → a-z)
  • マルチバイト文字にはmb_strtolower()を使用
  • 元の文字列は変更されない

関連関数:

  • strtoupper(): 大文字に変換
  • ucfirst(): 最初の文字を大文字に
  • ucwords(): 各単語の最初を大文字に
  • mb_strtolower(): マルチバイト対応版
  • lcfirst(): 最初の文字を小文字に

大文字小文字を区別しない比較:

// 方法1: strtolower()を使用
if (strtolower($str1) === strtolower($str2)) {
    // 一致
}

// 方法2: strcasecmp()を使用
if (strcasecmp($str1, $str2) === 0) {
    // 一致
}

パフォーマンス:

  • 非常に高速(C言語レベルで最適化)
  • 大量のデータでも効率的

strtolower()は、文字列処理の基本中の基本です。データの正規化や比較処理など、様々な場面で活躍する関数なので、マルチバイト文字の扱いに注意しながら、適切に使いこなしましょう!

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