🔢

Dartで全角数字を半角数字に変換する方法

に公開

Dartで全角数字を半角数字に変換する方法

はじめに

日本語を扱うアプリケーション開発において、全角文字と半角文字の変換は避けて通れない課題の一つです。
特に、ユーザー入力やURL処理において、全角数字(0123...)を半角数字(0123...)に統一する必要があるケースは多々あります。

本記事では、Dartにおける効率的な全角数字変換の実装方法と、その背景にあるUnicode文字コードの仕組みについて詳しく解説します。

問題の背景

なぜ全角・半角変換が必要なのか?

  • ユーザビリティの向上: 日本語入力時に無意識に全角数字が入力されることがある
  • データの統一性: データベースやAPI処理において文字形式を統一する必要がある
  • URL処理: ルーティング処理で数値パラメータを正確に解析する必要がある

実装の詳細解説

1. 基本的なString拡張メソッド

extension ExtString on String {
  String convertFullWidthToHalfWidth() {
    final buffer = StringBuffer();

    for (final i = 0; i < length; i++) {
      final char = this[i];
      final codeUnit = char.codeUnitAt(0);

      // 全角数字(0xFF10-0xFF19)を半角(0x30-0x39)に変換
      if (codeUnit >= 0xFF10 && codeUnit <= 0xFF19) {
        buffer.write(String.fromCharCode(codeUnit - 0xFEE0));
      } else if (codeUnit >= 0x30 && codeUnit <= 0x39) {
        // 既に半角数字の場合はそのまま
        buffer.write(char);
      } else {
        // 数字以外の文字が含まれている場合
        throw FormatException('$this: $char is not a number');
      }
    }

    return buffer.toString();
  }
}

2. Unicode文字コードの仕組み

全角数字と半角数字のコード範囲

文字種類 範囲 Unicodeコード
半角数字 0-9 0x30 - 0x39
全角数字 0-9 0xFF10 - 0xFF19

変換の数学的原理

全角数字から半角数字への変換は、単純な算術演算で実現できます:

半角コード = 全角コード - 0xFEE0
  • 全角の「5」(0xFF15) → 半角の「5」(0x35)
  • 計算: 0xFF15 - 0xFEE0 = 0x35

3. 実装のポイント

パフォーマンス最適化

  • StringBuffer使用: 文字列連結の効率化
  • 直接的な文字コード操作: 正規表現より高速

エラーハンドリング

// 数字以外の文字が含まれている場合
throw FormatException('$this: $char is not a number');

厳密な数字チェックにより、予期しない文字の混入を防止します。

URI処理への応用

URLパスでの全角数字検出

extension ExtUri on Uri {
  bool containsFullWidthDigits() {
    for (final segment in pathSegments) {
      for (final i = 0; i < segment.length; i++) {
        final codeUnit = segment.codeUnitAt(i);
        if (codeUnit >= 0xFF10 && codeUnit <= 0xFF19) {
          return true;
        }
      }
    }
    return false;
  }
}

パスセグメントの一括変換

List<String> pathSegmentsFullWidthToHalfWidth() {
  return pathSegments.map((segment) {
    try {
      return segment.convertFullWidthToHalfWidth();
    } on FormatException {
      return segment; // 数字以外のセグメントはそのまま返す
    }
  }).toList();
}

使用例とテストケース

基本的な使用例

void main() {
  // 基本的な変換
  print('12345'.convertFullWidthToHalfWidth()); // "12345"
  
  // 混在パターン
  print('12345'.convertFullWidthToHalfWidth()); // "12345"
  
  // URI処理
  final uri = Uri.parse('/article/123');
  print(uri.containsFullWidthDigits()); // true
  print(uri.pathSegmentsFullWidthToHalfWidth()); // [article, 123]
}

エラーケースの処理

try {
  'abc123'.convertFullWidthToHalfWidth();
} on FormatException catch (e) {
  print('エラー: ${e.message}'); // "abc123: a is not a number"
}

まとめ

本記事で紹介した全角数字変換メソッドは、以下の特徴を持ちます:

  • 高パフォーマンス: 直接的な文字コード操作による効率的な処理
  • 安全性: 厳密なエラーチェックによる予期しない動作の防止
  • 拡張性: Dart ExtensionによるStringUriクラスの自然な拡張

日本語を扱うFlutterアプリケーションにおいて、このような文字変換処理は必須の機能です。
Unicode文字コードの仕組みを理解することで、より堅牢で効率的な国際化対応アプリケーションを構築できるでしょう。

GitHubで編集を提案

Discussion