SMSカウンターとは?GSM 7ビットとUCS-2エンコーディングの理解

17 Jun 2026 562 words

SMSカウンターとは?

SMSカウンターは、メッセージに含まれる文字数を計算し、エンコーディングタイプ(GSM 7ビットまたはUCS-2)を検出し、メッセージがいくつのSMSセグメントに分割されるかを判断するツールです。モバイルキャリアはメッセージ単位ではなくセグメント単位で課金するため、これは重要です。単一SMSの制限を超えると、警告なしにコストが2倍または3倍になる可能性があります。

通常の文字カウンターとは異なり、SMSカウンターはGSM 03.38で定義されたショートメッセージサービスの技術的制約を考慮します。テキストの長さだけでなく、含まれる文字と、それらがセルラーネットワークを介した送信のためにどのようにエンコードされる必要があるかを考慮します。

GSM 7ビットエンコーディングの仕組み

GSM 03.38仕様は、各7ビットでエンコードできる128文字のデフォルトアルファベットを定義しています。これには、大文字と小文字のラテン文字、数字、一般的な句読点、いくつかの特殊記号が含まれます。各文字が8ビットではなく7ビットのみを使用するため、1つのSMSは最大160文字まで収容できます。計算式は(140バイト × 8ビット)/ 7ビット/文字 です。

GSM 7ビット基本文字セット:

カテゴリ 文字
文字 A–Z, a–z
数字 0–9
句読点 @, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /
記号 :, ;, <, =, >, ?, ¡, ¿, ¤, £, ¥, §, ¨, ©, ®, ´, `, ^, ~, ¯
特殊 スペース、改行、復帰
拡張 ^, {, }, , [, ~, ], , €(エスケープバイトが必要)

^{}[]~| などの拡張GSM 7ビット文字は、文字の前にエスケープコード(0x1B)が必要です。このエスケープバイトはメッセージ内の容量を消費するため、各拡張文字は160文字の制限に対して実質的に2文字としてカウントされます。

UCS-2エンコーディング:7ビットでは不十分な場合

メッセージにGSM 7ビットアルファベット以外の文字(絵文字、カーリークォート、éü などのアクセント付き文字、 などのダッシュ、または任意のUnicode記号)が含まれる場合、メッセージ全体がUCS-2(16ビット)エンコーディングに切り替わります。UCS-2モードでは、各文字が16ビットを占有するため、単一SMSの容量が160文字から70文字に減少します。

UCS-2エンコーディングを強制する文字:

  • 絵文字とピクトグラフ(😊🚀❤️
  • カーリークォート(""''
  • 長いダッシュ(
  • GSM基本セットにないアクセント付き文字(ěřč
  • $£¥ 以外の通貨記号
  • 矢印(
  • 数学記号(
  • ほとんどのCJK(中国語、日本語、韓国語)文字

メッセージに1つでもUCS-2文字が含まれると、メッセージ全体が16ビットエンコーディングを使用します。ハイブリッドモードはありません。すべて7ビットまたはすべて16ビットのいずれかです。

マルチパートSMSとセグメント制限

メッセージが単一SMSの制限(GSM 160文字またはUCS-2 70文字)を超えると、キャリアはメッセージを複数のセグメントに分割します。各セグメントには再構成用の6バイトのユーザーデータヘッダー(UDH)が含まれ、利用可能なペイロード容量が減少します。

エンコーディング 単一SMS マルチパート(セグメントあたり)
GSM 7ビット 160文字 153文字
UCS-2 70文字 67文字

計算の仕組み:

GSM 7ビット マルチパート:
  セグメントあたりの文字数 = (140 - 6) × 8 / 7 = 153

UCS-2 マルチパート:
  セグメントあたりの文字数 = (140 - 6) / 2 = 67

GSM 7ビットエンコーディングの200文字メッセージは2つのセグメント(153 + 47)に分割されます。絵文字を含む150文字メッセージは3つのUCS-2セグメント(67 + 67 + 16)に分割されます。ほとんどのキャリアはセグメントごとに課金するため、これらの制限を理解することはコスト管理に役立ちます。

コード例

PHP:SMSセグメントをカウント

function countSmsSegments(string $text): array {
    $gsm7 = '@£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !"#¤%&\'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà';
    $gsm7ext = ['^', '{', '}', '\\', '[', '~', ']', '|', '€'];
    $isUcs2 = false;
    $extCount = 0;

    for ($i = 0; $i < mb_strlen($text); $i++) {
        $char = mb_substr($text, $i, 1);
        if (in_array($char, $gsm7ext)) {
            $extCount++;
        } elseif (mb_strpos($gsm7, $char) === false) {
            $isUcs2 = true;
            break;
        }
    }

    if ($isUcs2) {
        $maxPerSegment = 70;
        $segments = (int)ceil(mb_strlen($text) / $maxPerSegment);
        // マルチパートは制限を減らす
        if ($segments > 1) {
            $maxPerSegment = 67;
            $segments = (int)ceil(mb_strlen($text) / $maxPerSegment);
        }
        return ['encoding' => 'UCS-2', 'segments' => $segments, 'chars_per_segment' => $maxPerSegment];
    }

    $effectiveLength = mb_strlen($text) + $extCount;
    $maxPerSegment = 160;
    $segments = (int)ceil($effectiveLength / $maxPerSegment);
    if ($segments > 1) {
        $maxPerSegment = 153;
        $segments = (int)ceil($effectiveLength / $maxPerSegment);
    }
    return ['encoding' => 'GSM 7-bit', 'segments' => $segments, 'chars_per_segment' => $maxPerSegment];
}

JavaScript:SMSエンコーディングを検出

const GSM7_BASIC = new Set(
  '@£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !"#¤%&\'()*+,-./0123456789:;<=>?¡' +
  'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà'.split('')
);
const GSM7_EXT = new Set(['^', '{', '}', '\\', '[', '~', ']', '|', '€']);

function detectSmsEncoding(text) {
  let extCount = 0;
  for (const char of text) {
    if (GSM7_EXT.has(char)) {
      extCount++;
    } else if (!GSM7_BASIC.has(char)) {
      return { encoding: 'UCS-2', extCount: 0 };
    }
  }
  return { encoding: 'GSM 7-bit', extCount };
}

const result = detectSmsEncoding('Hello World! €50');
console.log(result); // { encoding: 'GSM 7-bit', extCount: 1 }

Python:SMSパーツを計算

def sms_parts(text: str) -> dict:
    gsm7_basic = set('@£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !"#¤%&\'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà')
    gsm7_ext = {'^', '{', '}', '\\', '[', '~', ']', '|', '€'}
    
    is_ucs2 = False
    ext_count = 0
    
    for char in text:
        if char in gsm7_ext:
            ext_count += 1
        elif char not in gsm7_basic:
            is_ucs2 = True
            break
    
    if is_ucs2:
        limit = 70 if len(text) <= 70 else 67
        parts = (len(text) + limit - 1) // limit
        return {'encoding': 'UCS-2', 'parts': parts, 'chars_per_part': limit}
    
    effective = len(text) + ext_count
    limit = 160 if effective <= 160 else 153
    parts = (effective + limit - 1) // limit
    return {'encoding': 'GSM 7-bit', 'parts': parts, 'chars_per_part': limit}

print(sms_parts('Hello World'))  # 1 part, GSM 7-bit
print(sms_parts('Hello 😊 World'))  # UCS-2 encoding triggered

SMSエンコーディングが開発者にとって重要な理由

SMS通知を送信するアプリケーション(二要素認証コード、予約リマインダー、マーケティングキャンペーンなど)を構築する場合、SMSエンコーディングを理解することで、配信可能性とコストの両方を制御できます。

開発者向けの重要なポイント:

  • 予期しないマルチパート課金を避けるために、送信前に常にメッセージ長を検証する
  • 可能な場合はUCS-2文字を削除または置換して、メッセージをGSM 7ビットに保つ
  • [] などの拡張文字でテストする — これらは基本GSM文字とは異なる圧縮方法になる
  • マルチパート容量を見積もる際は、6バイトのUDHオーバーヘッドを考慮する
  • 開発とテスト中は専用のSMSカウンターツールの使用を検討する

オンラインツール

Help2CodeのSMSカウンターは、リアルタイムの文字カウント、エンコーディング検出、セグメントプレビューを提供します。メッセージを貼り付けると、GSM 7ビットとUCS-2エンコーディングのどちらを使用しているか、必要なセグメント数、各セグメントの正確な区切り位置が即座に表示されます。色分けされたエンコーディングプレビューは、どの文字がUnicodeモードをトリガーし、どの文字が7ビットで安全かを示します。

結論

SMSカウンターは、プログラムでテキストメッセージを送信する人、または予期しないキャリア課金を避けたい人にとって不可欠なユーティリティです。GSM 7ビットとUCS-2エンコーディングの違いを理解し、マルチパートセグメンテーションの仕組みを知ることで、よりコスト効果の高いSMSアプリケーションを作成し、配信問題をより迅速にデバッグできます。本番環境で送信する前に、SMSカウンターツールを使用してメッセージをテストしてください。


About this article

SMSカウンターとは何か、GSM 7ビットとUCS-2エンコーディングの仕組み、そして文字数がSMS配信と課金に重要な理由を学びます。


Related Articles


Related Tools

Help2Code Logo
Menu