[PHP]strlen関数を完全解説!文字列の長さを取得する方法

PHP

こんにちは!今回は、PHPの標準関数であるstrlen()について詳しく解説していきます。文字列の長さを取得する、最も基本的で重要な関数の一つです!

strlen関数とは?

strlen()関数は、文字列のバイト数(長さ)を返す関数です。

シンプルですが、バリデーション、文字数制限、データ処理など、あらゆる場面で使用される基本的な関数です!

基本的な構文

strlen(string $string): int
  • $string: 長さを取得する文字列
  • 戻り値: 文字列のバイト数(整数)

基本的な使用例

シンプルな使用例

// 英数字の長さ
$text = "Hello";
echo strlen($text) . "\n";  // 5

// 空文字列
$empty = "";
echo strlen($empty) . "\n";  // 0

// 数値は文字列に変換される
$number = 12345;
echo strlen($number) . "\n";  // 5

// スペースもカウントされる
$withSpaces = "Hello World";
echo strlen($withSpaces) . "\n";  // 11

日本語(マルチバイト文字)の扱い

// 日本語文字列
$japanese = "こんにちは";
echo strlen($japanese) . "\n";  // 15(UTF-8では1文字3バイト)

// mb_strlen()との違い
echo mb_strlen($japanese) . "\n";  // 5(文字数)

// 英数字と日本語の混在
$mixed = "Hello世界";
echo strlen($mixed) . "\n";  // 11(5 + 6バイト)
echo mb_strlen($mixed) . "\n";  // 7(文字数)

NULL文字の扱い

// NULL文字を含む文字列
$withNull = "Hello\0World";
echo strlen($withNull) . "\n";  // 11(NULL文字もカウント)

// 表示は途中で切れる
echo $withNull . "\n";  // Hello(NULL以降は表示されない)

実践的な使用例

例1: 入力バリデーション

class InputValidator {
    /**
     * 文字列長のチェック
     */
    public static function validateLength($input, $min, $max) {
        $length = strlen($input);
        
        if ($length < $min) {
            return [
                'valid' => false,
                'error' => "最低{$min}文字必要です(現在: {$length}文字)"
            ];
        }
        
        if ($length > $max) {
            return [
                'valid' => false,
                'error' => "最大{$max}文字までです(現在: {$length}文字)"
            ];
        }
        
        return ['valid' => true];
    }
    
    /**
     * パスワードの強度チェック
     */
    public static function validatePassword($password) {
        $length = strlen($password);
        
        if ($length < 8) {
            return [
                'valid' => false,
                'error' => 'パスワードは8文字以上必要です',
                'strength' => 'weak'
            ];
        }
        
        if ($length < 12) {
            $strength = 'medium';
        } elseif ($length < 16) {
            $strength = 'strong';
        } else {
            $strength = 'very_strong';
        }
        
        return [
            'valid' => true,
            'length' => $length,
            'strength' => $strength
        ];
    }
    
    /**
     * 空文字列チェック
     */
    public static function isEmpty($input) {
        return strlen(trim($input)) === 0;
    }
    
    /**
     * ユーザー名のバリデーション
     */
    public static function validateUsername($username) {
        $length = strlen($username);
        
        if ($length < 3) {
            return [
                'valid' => false,
                'error' => 'ユーザー名は3文字以上必要です'
            ];
        }
        
        if ($length > 20) {
            return [
                'valid' => false,
                'error' => 'ユーザー名は20文字以内にしてください'
            ];
        }
        
        if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
            return [
                'valid' => false,
                'error' => 'ユーザー名は英数字とアンダースコアのみ使用できます'
            ];
        }
        
        return ['valid' => true];
    }
}

// 使用例
$result = InputValidator::validateLength("test", 5, 20);
print_r($result);
// valid => false, error => "最低5文字必要です(現在: 4文字)"

$result = InputValidator::validatePassword("pass");
print_r($result);
// valid => false, error => "パスワードは8文字以上必要です"

$result = InputValidator::validatePassword("SecurePassword123");
print_r($result);
// valid => true, length => 17, strength => very_strong

var_dump(InputValidator::isEmpty("   "));  // true
var_dump(InputValidator::isEmpty("test"));  // false

例2: テキストの切り詰め

class TextTruncator {
    /**
     * 指定長で切り詰め
     */
    public static function truncate($text, $maxLength, $suffix = '...') {
        if (strlen($text) <= $maxLength) {
            return $text;
        }
        
        $truncated = substr($text, 0, $maxLength - strlen($suffix));
        return $truncated . $suffix;
    }
    
    /**
     * 単語の途中で切らない切り詰め
     */
    public static function truncateWords($text, $maxLength, $suffix = '...') {
        if (strlen($text) <= $maxLength) {
            return $text;
        }
        
        $truncated = substr($text, 0, $maxLength - strlen($suffix));
        
        // 最後のスペースを探す
        $lastSpace = strrpos($truncated, ' ');
        
        if ($lastSpace !== false && $lastSpace > $maxLength * 0.7) {
            $truncated = substr($truncated, 0, $lastSpace);
        }
        
        return $truncated . $suffix;
    }
    
    /**
     * 文の途中で切らない切り詰め
     */
    public static function truncateSentences($text, $maxLength) {
        if (strlen($text) <= $maxLength) {
            return $text;
        }
        
        $truncated = substr($text, 0, $maxLength);
        
        // 最後の句点を探す
        $lastPeriod = max(
            strrpos($truncated, '.'),
            strrpos($truncated, '。')
        );
        
        if ($lastPeriod !== false && $lastPeriod > $maxLength * 0.5) {
            return substr($text, 0, $lastPeriod + 1);
        }
        
        return self::truncateWords($text, $maxLength);
    }
    
    /**
     * 中央を省略
     */
    public static function truncateMiddle($text, $maxLength) {
        if (strlen($text) <= $maxLength) {
            return $text;
        }
        
        $ellipsis = '...';
        $sideLength = floor(($maxLength - strlen($ellipsis)) / 2);
        
        $start = substr($text, 0, $sideLength);
        $end = substr($text, -$sideLength);
        
        return $start . $ellipsis . $end;
    }
}

// 使用例
$longText = "This is a very long text that needs to be truncated for display purposes.";

echo TextTruncator::truncate($longText, 30) . "\n";
// This is a very long text th...

echo TextTruncator::truncateWords($longText, 30) . "\n";
// This is a very long text...

$path = "/very/long/path/to/some/file/document.pdf";
echo TextTruncator::truncateMiddle($path, 25) . "\n";
// /very/long/...ument.pdf

例3: データサイズの表示

class DataSizeFormatter {
    /**
     * バイト数を人間が読みやすい形式に変換
     */
    public static function formatBytes($bytes, $precision = 2) {
        $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
        $unitIndex = 0;
        
        while ($bytes >= 1024 && $unitIndex < count($units) - 1) {
            $bytes /= 1024;
            $unitIndex++;
        }
        
        return number_format($bytes, $precision) . ' ' . $units[$unitIndex];
    }
    
    /**
     * 文字列のバイト数を表示
     */
    public static function getStringSize($string) {
        $bytes = strlen($string);
        return [
            'bytes' => $bytes,
            'formatted' => self::formatBytes($bytes)
        ];
    }
    
    /**
     * ファイルサイズの推定
     */
    public static function estimateFileSize($content) {
        $size = strlen($content);
        
        return [
            'bytes' => $size,
            'formatted' => self::formatBytes($size),
            'kilobytes' => round($size / 1024, 2),
            'megabytes' => round($size / (1024 * 1024), 2)
        ];
    }
}

// 使用例
$text = str_repeat("Hello World! ", 1000);

print_r(DataSizeFormatter::getStringSize($text));
/*
Array (
    [bytes] => 13000
    [formatted] => 12.70 KB
)
*/

$largeData = str_repeat("A", 1024 * 1024 * 5);  // 5MB
print_r(DataSizeFormatter::estimateFileSize($largeData));
/*
Array (
    [bytes] => 5242880
    [formatted] => 5.00 MB
    [kilobytes] => 5120
    [megabytes] => 5
)
*/

例4: プログレスバーの表示

class ProgressBar {
    private $total;
    private $width;
    
    public function __construct($total, $width = 50) {
        $this->total = $total;
        $this->width = $width;
    }
    
    /**
     * プログレスバーを描画
     */
    public function display($current) {
        $percentage = ($current / $this->total) * 100;
        $filled = round(($current / $this->total) * $this->width);
        $empty = $this->width - $filled;
        
        $bar = str_repeat('=', $filled) . str_repeat(' ', $empty);
        
        // バーの長さを確認
        $barLength = strlen($bar);
        
        $display = sprintf(
            "\r[%s] %3d%% (%d/%d)",
            $bar,
            (int)$percentage,
            $current,
            $this->total
        );
        
        echo $display;
        
        if ($current >= $this->total) {
            echo "\n";
        }
    }
    
    /**
     * 推定残り時間付き
     */
    public function displayWithETA($current, $startTime) {
        $percentage = ($current / $this->total) * 100;
        $filled = round(($current / $this->total) * $this->width);
        $empty = $this->width - $filled;
        
        $bar = str_repeat('=', $filled) . str_repeat(' ', $empty);
        
        $elapsed = time() - $startTime;
        
        if ($current > 0) {
            $rate = $current / $elapsed;
            $remaining = ($this->total - $current) / $rate;
            $eta = sprintf('%02d:%02d:%02d', 
                floor($remaining / 3600),
                floor(($remaining % 3600) / 60),
                $remaining % 60
            );
        } else {
            $eta = '--:--:--';
        }
        
        $display = sprintf(
            "\r[%s] %3d%% ETA: %s",
            $bar,
            (int)$percentage,
            $eta
        );
        
        // 表示がターミナル幅を超えないようチェック
        if (strlen($display) > 80) {
            $display = substr($display, 0, 80);
        }
        
        echo $display;
        
        if ($current >= $this->total) {
            echo "\n";
        }
    }
}

// 使用例(シミュレーション)
/*
$progress = new ProgressBar(100);
$startTime = time();

for ($i = 0; $i <= 100; $i++) {
    $progress->displayWithETA($i, $startTime);
    usleep(50000);  // 0.05秒待機
}
*/

例5: 文字列の統計情報

class StringStatistics {
    /**
     * 文字列の統計情報を取得
     */
    public static function analyze($text) {
        $length = strlen($text);
        $trimmedLength = strlen(trim($text));
        
        $wordCount = str_word_count($text);
        $lineCount = substr_count($text, "\n") + 1;
        
        $alphaCount = preg_match_all('/[a-zA-Z]/', $text);
        $digitCount = preg_match_all('/[0-9]/', $text);
        $spaceCount = substr_count($text, ' ');
        $punctuationCount = preg_match_all('/[.,!?;:]/', $text);
        
        return [
            'total_length' => $length,
            'trimmed_length' => $trimmedLength,
            'word_count' => $wordCount,
            'line_count' => $lineCount,
            'alpha_count' => $alphaCount,
            'digit_count' => $digitCount,
            'space_count' => $spaceCount,
            'punctuation_count' => $punctuationCount,
            'average_word_length' => $wordCount > 0 ? round($alphaCount / $wordCount, 2) : 0
        ];
    }
    
    /**
     * 読了時間を推定
     */
    public static function estimateReadingTime($text, $wordsPerMinute = 200) {
        $wordCount = str_word_count($text);
        $minutes = ceil($wordCount / $wordsPerMinute);
        
        return [
            'word_count' => $wordCount,
            'minutes' => $minutes,
            'formatted' => $minutes . '分'
        ];
    }
    
    /**
     * 文字列の密度を計算
     */
    public static function calculateDensity($text) {
        $length = strlen($text);
        
        if ($length === 0) {
            return 0;
        }
        
        $nonSpaceLength = strlen(str_replace(' ', '', $text));
        
        return round(($nonSpaceLength / $length) * 100, 2);
    }
}

// 使用例
$article = <<<TEXT
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco.
TEXT;

print_r(StringStatistics::analyze($article));
/*
Array (
    [total_length] => 183
    [trimmed_length] => 181
    [word_count] => 26
    [line_count] => 3
    [alpha_count] => 142
    [digit_count] => 0
    [space_count] => 25
    [punctuation_count] => 3
    [average_word_length] => 5.46
)
*/

print_r(StringStatistics::estimateReadingTime($article));
/*
Array (
    [word_count] => 26
    [minutes] => 1
    [formatted] => 1分
)
*/

echo "密度: " . StringStatistics::calculateDensity($article) . "%\n";
// 密度: 86.34%

例6: パスワード強度メーター

class PasswordStrengthMeter {
    /**
     * パスワード強度を計算
     */
    public static function calculateStrength($password) {
        $length = strlen($password);
        $score = 0;
        
        // 長さによるスコア
        if ($length >= 8) $score += 20;
        if ($length >= 12) $score += 20;
        if ($length >= 16) $score += 20;
        
        // 文字の種類によるスコア
        if (preg_match('/[a-z]/', $password)) $score += 10;
        if (preg_match('/[A-Z]/', $password)) $score += 10;
        if (preg_match('/[0-9]/', $password)) $score += 10;
        if (preg_match('/[^a-zA-Z0-9]/', $password)) $score += 10;
        
        // 強度レベルを判定
        if ($score < 40) {
            $level = 'weak';
            $label = '弱い';
        } elseif ($score < 70) {
            $level = 'medium';
            $label = '普通';
        } elseif ($score < 90) {
            $level = 'strong';
            $label = '強い';
        } else {
            $level = 'very_strong';
            $label = '非常に強い';
        }
        
        return [
            'length' => $length,
            'score' => $score,
            'level' => $level,
            'label' => $label,
            'percentage' => min(100, $score)
        ];
    }
    
    /**
     * 強度メーターを表示
     */
    public static function displayMeter($password) {
        $strength = self::calculateStrength($password);
        
        $barLength = 30;
        $filled = round(($strength['percentage'] / 100) * $barLength);
        $empty = $barLength - $filled;
        
        $bar = str_repeat('█', $filled) . str_repeat('░', $empty);
        
        return sprintf(
            "[%s] %s (%d%%)",
            $bar,
            $strength['label'],
            $strength['percentage']
        );
    }
}

// 使用例
$passwords = [
    'pass',
    'password',
    'Password1',
    'P@ssw0rd123',
    'MyV3ry$tr0ng&P@ssw0rd!'
];

foreach ($passwords as $password) {
    echo "パスワード: {$password}\n";
    echo StringStatistics::displayMeter($password) . "\n";
    print_r(PasswordStrengthMeter::calculateStrength($password));
    echo "\n";
}

例7: CSVデータの検証

class CsvValidator {
    /**
     * CSVフィールドの長さを検証
     */
    public static function validateFieldLengths($csvLine, $maxLengths) {
        $fields = str_getcsv($csvLine);
        $errors = [];
        
        foreach ($fields as $index => $field) {
            $fieldLength = strlen($field);
            $maxLength = $maxLengths[$index] ?? null;
            
            if ($maxLength !== null && $fieldLength > $maxLength) {
                $errors[] = [
                    'field' => $index,
                    'length' => $fieldLength,
                    'max_length' => $maxLength,
                    'exceeded_by' => $fieldLength - $maxLength
                ];
            }
        }
        
        return [
            'valid' => empty($errors),
            'errors' => $errors
        ];
    }
    
    /**
     * 固定長フォーマットの検証
     */
    public static function validateFixedLength($line, $expectedLength) {
        $actualLength = strlen($line);
        
        if ($actualLength !== $expectedLength) {
            return [
                'valid' => false,
                'expected' => $expectedLength,
                'actual' => $actualLength,
                'difference' => $actualLength - $expectedLength
            ];
        }
        
        return ['valid' => true];
    }
    
    /**
     * データサイズの確認
     */
    public static function checkDataSize($data, $maxBytes) {
        $size = strlen($data);
        
        if ($size > $maxBytes) {
            return [
                'valid' => false,
                'size' => $size,
                'max_size' => $maxBytes,
                'exceeded_by' => $size - $maxBytes,
                'formatted_size' => DataSizeFormatter::formatBytes($size)
            ];
        }
        
        return [
            'valid' => true,
            'size' => $size,
            'formatted_size' => DataSizeFormatter::formatBytes($size)
        ];
    }
}

// 使用例
$csvLine = "John Doe,john@example.com,This is a very long comment field";
$maxLengths = [20, 50, 30];  // 各フィールドの最大長

$result = CsvValidator::validateFieldLengths($csvLine, $maxLengths);
print_r($result);

$fixedLine = "123456789012345";
$result = CsvValidator::validateFixedLength($fixedLine, 15);
var_dump($result['valid']);  // true

$largeData = str_repeat("test", 10000);
$result = CsvValidator::checkDataSize($largeData, 50000);
print_r($result);

count()との違い

// strlen(): 文字列の長さ(バイト数)
$text = "Hello";
echo strlen($text) . "\n";  // 5

// count(): 配列の要素数
$array = ['a', 'b', 'c'];
echo count($array) . "\n";  // 3

// 文字列にcount()を使用すると警告
// echo count($text);  // Warning

// 配列にstrlen()を使用するとエラー
// echo strlen($array);  // TypeError

mb_strlen()との違い

$text = "こんにちは世界";

// strlen(): バイト数
echo "strlen: " . strlen($text) . "\n";
// 21 (UTF-8で各文字3バイト)

// mb_strlen(): 文字数
echo "mb_strlen: " . mb_strlen($text) . "\n";
// 7

// 英数字の場合は同じ
$english = "Hello World";
echo "strlen: " . strlen($english) . "\n";  // 11
echo "mb_strlen: " . mb_strlen($english) . "\n";  // 11

パフォーマンス

// strlen()は非常に高速(O(1))
$text = str_repeat("a", 1000000);

$start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
    strlen($text);
}
$time = microtime(true) - $start;

echo "処理時間: {$time}秒\n";
// 非常に高速(文字列の長さは内部で保持されている)

まとめ

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

できること:

  • 文字列のバイト数を取得
  • 空文字列の判定
  • 文字列の長さ制限チェック

注意点:

  • バイト数を返す(文字数ではない)
  • マルチバイト文字にはmb_strlen()を使用
  • NULL文字も含めてカウント

推奨される使用場面:

  • 入力バリデーション
  • テキストの切り詰め
  • データサイズの計算
  • プログレス表示
  • パスワード強度チェック

関連関数:

  • mb_strlen(): マルチバイト対応の文字数取得
  • count(): 配列の要素数取得
  • substr(): 部分文字列の取得
  • str_word_count(): 単語数のカウント

パフォーマンス:

  • O(1)の時間複雑度(非常に高速)
  • 文字列の長さは内部で保持されている

strlen()は最も基本的な文字列関数の一つですが、マルチバイト文字を扱う場合はmb_strlen()の使用を検討しましょう。適切に使い分けることで、正確なデータ処理が可能になります!

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