PHP / 함수 / strlen(), mb_strlen() / 문자열의 길이 구하는 함수

strlen()은 문자열의 바이트 수를, mb_strlen()은 지정한 인코딩에 따라 해석한 문자 수를 반환합니다. UTF-8의 가나다는 strlen()으로 9, mb_strlen()으로 3입니다. 사용자에게 한 글자로 보이는 결합 문자까지 세려면 두 함수와 별개로 grapheme_strlen() 같은 문자 묶음 단위의 처리가 필요할 수 있습니다.

strlen()과 mb_strlen() 결과 비교

아래 예제는 UTF-8로 저장한 PHP 파일을 기준으로 합니다. mb_strlen()에는 mbstring 확장이 필요합니다. PHP가 설치된 환경에서 length.php로 저장하고 php length.php로 실행하세요. 뒤의 예제도 각각 별도 파일에 저장해 실행할 수 있습니다.

<?php
if (!extension_loaded('mbstring')) {
    exit("mbstring 확장을 활성화하세요." . PHP_EOL);
}
foreach (['123 abc', '가나다', ''] as $text) {
    echo json_encode([
        'text' => $text,
        'bytes' => strlen($text),
        'characters' => mb_strlen($text, 'UTF-8'),
    ], JSON_UNESCAPED_UNICODE), PHP_EOL;
}
UTF-8 문자열 strlen() mb_strlen(..., "UTF-8")
123 abc 7 7
가나다 9 3
빈 문자열 0 0

첫 줄의 공백도 길이에 포함됩니다. 가나다의 각 음절은 이 UTF-8 문자열에서 3바이트이므로 전체가 9바이트입니다. 모든 문자나 모든 인코딩에서 한 글자가 3바이트라는 뜻은 아닙니다. 두 함수는 계산한 정수를 반환하므로 echo나 JSON 출력으로 결과를 따로 표시합니다.

파일·전송 데이터의 바이트 제한에는 strlen()이, UTF-8 문자 수 제한에는 mb_strlen()이 목적에 맞을 수 있습니다. 저장소가 어떤 단위로 제한하는지 먼저 확인해야 합니다. 함수 정의는 strlen() 문서와 mb_strlen() 문서를 참고하세요.

인코딩 지정은 문자열 변환이 아닙니다

mb_strlen()의 두 번째 인수는 현재 바이트열을 어떤 인코딩으로 읽을지 지정합니다. UTF-8 문자열에 EUC-KR을 지정한다고 해서 EUC-KR로 바뀌지 않습니다. 실제 데이터의 인코딩과 다른 값을 지정한 결과는 올바른 문자 수로 사용할 수 없습니다.

<?php
$utf8 = '가나다';
$euckr = mb_convert_encoding($utf8, 'EUC-KR', 'UTF-8');
if ($euckr === false) {
    exit("변환에 실패했습니다." . PHP_EOL);
}
echo strlen($utf8), PHP_EOL;
echo mb_strlen($utf8, 'UTF-8'), PHP_EOL;
echo strlen($euckr), PHP_EOL;
echo mb_strlen($euckr, 'EUC-KR'), PHP_EOL;

출력은 순서대로 9, 3, 6, 3입니다. 먼저 UTF-8인 가나다를 실제 EUC-KR 바이트열로 변환했으므로, EUC-KR의 6바이트도 해당 인코딩으로 세면 3문자입니다. EUC-KR로 세면 가나다가 6문자라는 설명은 바이트 수와 문자 수를 혼동한 것입니다. 변환 규칙은 mb_convert_encoding() 문서에 있습니다.

encoding을 생략하거나 null을 주면 mbstring의 내부 인코딩을 사용합니다. HTML의 meta charset을 자동으로 읽어서 정하는 것이 아닙니다. 기본값은 mb_internal_encoding()으로 확인할 수 있지만, UTF-8 입력을 처리하는 예제처럼 인코딩이 정해져 있으면 함수에 명시하는 편이 의도를 분명하게 합니다.

화면에서 한 글자처럼 보이는 문자 세기

유니코드에서는 기본 문자에 결합 기호가 붙어 한 글자처럼 표시될 수 있습니다. UTF-8의 mb_strlen()은 코드 포인트 단위로 세므로 화면상의 글자 수와 항상 같지는 않습니다. 사용자에게 보이는 문자 묶음인 자소 군집 단위가 필요하면 intl 확장의 grapheme_strlen()을 검토하세요.

<?php
if (!function_exists('grapheme_strlen')) {
    exit("intl 확장이 필요합니다." . PHP_EOL);
}
$text = "e\u{0301}"; // e + 결합 악센트
echo strlen($text), PHP_EOL;
echo mb_strlen($text, 'UTF-8'), PHP_EOL;
echo grapheme_strlen($text), PHP_EOL;

이 코드는 PHP의 유니코드 이스케이프로 e와 결합 악센트를 만듭니다. 결과는 바이트 수 3, 코드 포인트 수 2, 자소 군집 수 1입니다. 모양이 비슷하다고 바이트열까지 같다고 판단하면 안 되며, 이모지도 결합 방식에 따라 여러 코드 포인트가 한 묶음으로 보일 수 있습니다.

grapheme_strlen()에는 유효한 UTF-8 문자열을 전달해야 하며, 실패 시 false 또는 null을 반환할 수 있습니다. 함수가 없으면 위 예제는 안내 문장으로 종료합니다. 실제 서비스의 글자 수 정책이 바이트·코드 포인트·자소 군집 중 어느 것인지 먼저 정하고 클라이언트와 서버의 검증 기준을 맞추세요.

입력 길이 검사와 mbstring 오류 점검

길이 검사 전에 입력의 자료형과 인코딩을 확인해야 합니다. 다음 예제는 이미 문자열인 $name을 대상으로 유효한 UTF-8인지 확인한 뒤 최대 2문자 조건을 적용합니다. 앞의 예제처럼 mbstring이 활성화되어 있어야 합니다.

<?php
$name = '가나다';
if (!mb_check_encoding($name, 'UTF-8')) {
    echo "UTF-8 입력이 아닙니다.", PHP_EOL;
} elseif (mb_strlen($name, 'UTF-8') > 2) {
    echo "2문자 이하로 입력하세요.", PHP_EOL;
} else {
    echo "길이 조건을 통과했습니다.", PHP_EOL;
}

가나다는 3문자이므로 2문자 이하 안내가 출력됩니다. 값을 가나로 바꾸면 통과 문장이 출력됩니다. 길이 검사만으로 필수 입력이나 공백 허용, HTML 출력 안전성이 모두 해결되지는 않으므로 각 조건은 필요한 곳에서 별도로 처리하세요. mb_check_encoding()은 지정한 인코딩으로 유효한 바이트열인지 검사하는 함수입니다.

Call to undefined function mb_strlen() 오류가 나면 글자 수 공식을 바꾸기보다 현재 PHP에 mbstring이 로드되었는지 먼저 확인하세요. 명령줄의 php -m에서 모듈을 확인할 수 있고, 웹과 CLI는 서로 다른 설정을 사용할 수 있습니다. 활성화 절차는 PHP 설치 방식에 맞춰 mbstring 설치 문서를 확인해야 합니다. 설정 변경 후에는 실제 코드를 실행하는 환경에서 함수를 다시 검사하세요.

지원하지 않는 인코딩 이름은 PHP 8 이상에서 ValueError를 발생시킬 수 있습니다. 사용자가 입력한 임의의 이름을 그대로 신뢰하지 말고 앱에서 허용한 인코딩을 사용하세요. 한글이 깨지거나 결과가 예상과 다르면 파일 저장 형식·입력 데이터의 실제 인코딩·함수에 넘긴 인코딩이 일치하는지 차례대로 확인합니다.