入力値の正規化

にメンテナンス済み

kintone を業務で使っていると、同じ意味のデータなのに「全角で入力された電話番号」と「半角で入力された電話番号」が混在し、検索や集計で不都合が生じることがあります。また、フィールド前後に不要な空白が入っているせいでルックアップが一致しない、といったトラブルもよく発生します。

こうした問題は、レコードの保存時に入力値を自動的に正規化することで解決できます。

この記事では、全角→半角変換空白のトリムカタカナ→ひらがな変換など、実務で役立つ入力値の正規化パターンを JavaScript で実装する方法を紹介します。

全角英数字→半角英数字の変換

基本の変換関数

全角の英数字・記号を半角に変換する汎用関数です。

zen2han.js
/**
 * 全角英数字・記号を半角に変換する
 * @param { string } str - 変換対象の文字列
 * @returns { string } 変換後の文字列
 */
const toHalfWidth = (str) => {
  if (!str) return str;
  return str.replace(/[A-Za-z0-9]/g, (char) => {
    return String.fromCharCode(char.charCodeAt(0) - 0xFEE0);
  });
};
変換範囲について

上記の関数は英大文字(A-Z)、英小文字(a-z)、数字(0-9)を変換対象としています。全角スペースや全角記号(!、@ など)も含めたい場合は、正規表現を [!-~] に変更してください。

保存時に自動変換を適用する

auto-normalize.js
(() => {
  'use strict';

  /**
   * 全角英数字・記号を半角に変換する
   * @param { string } str - 変換対象の文字列
   * @returns { string } 変換後の文字列
   */
  const toHalfWidth = (str) => {
    if (!str) return str;
    return str.replace(/[!-~]/g, (char) => {
      return String.fromCharCode(char.charCodeAt(0) - 0xFEE0);
    });
  };

  // 正規化対象のフィールドコード一覧
  const TARGET_FIELDS = ['電話番号', '郵便番号', 'FAX', 'メールアドレス'];

  const events = [
    'app.record.create.submit',
    'app.record.edit.submit',
    'mobile.app.record.create.submit',
    'mobile.app.record.edit.submit',
  ];

  kintone.events.on(events, (event) => {
    const record = event.record;

    TARGET_FIELDS.forEach((fieldCode) => {
      if (record[fieldCode] && record[fieldCode].value) {
        record[fieldCode].value = toHalfWidth(record[fieldCode].value);
      }
    });

    return event;
  });
})();
チェック

正規化対象のフィールドコードを配列で管理することで、対象フィールドの追加や削除が容易になります。定数として切り出しておけば、メンテナンスもしやすくなります。

前後の空白を除去(トリム)

基本のトリム処理

フィールドの前後に含まれる半角・全角スペースやタブを除去します。

trim-fields.js
(() => {
  'use strict';

  /**
   * 文字列の前後から半角・全角スペース・タブを除去する
   * @param { string } str - トリム対象の文字列
   * @returns { string } トリム後の文字列
   */
  const trimAll = (str) => {
    if (!str) return str;
    return str.replace(/^[\s\u3000]+|[\s\u3000]+$/g, '');
  };

  // トリム対象のフィールドコード一覧
  const TRIM_FIELDS = ['会社名', '部署名', '担当者名', '商品コード'];

  const events = [
    'app.record.create.submit',
    'app.record.edit.submit',
  ];

  kintone.events.on(events, (event) => {
    const record = event.record;

    TRIM_FIELDS.forEach((fieldCode) => {
      if (record[fieldCode] && record[fieldCode].value) {
        record[fieldCode].value = trimAll(record[fieldCode].value);
      }
    });

    return event;
  });
})();
チェック

\s は半角スペース・タブ・改行などを含む正規表現クラスです。\u3000 は全角スペースの Unicode コードポイントです。これらを組み合わせることで、あらゆる種類の空白文字を除去できます。

全角カタカナ→ひらがな変換

フリガナフィールドの表記を統一するために、全角カタカナをひらがなに変換するパターンです。

katakana2hiragana.js
(() => {
  'use strict';

  /**
   * 全角カタカナをひらがなに変換する
   * @param { string } str - 変換対象の文字列
   * @returns { string } 変換後の文字列
   */
  const toHiragana = (str) => {
    if (!str) return str;
    return str.replace(/[\u30A1-\u30F6]/g, (char) => {
      return String.fromCharCode(char.charCodeAt(0) - 0x60);
    });
  };

  const events = [
    'app.record.create.submit',
    'app.record.edit.submit',
  ];

  kintone.events.on(events, (event) => {
    const record = event.record;

    if (record['フリガナ'] && record['フリガナ'].value) {
      record['フリガナ'].value = toHiragana(record['フリガナ'].value);
    }

    return event;
  });
})();
チェック

カタカナ→ひらがな変換は表記の統一に便利ですが、逆に「カタカナで統一したい」という業務ルールの場合は変換方向を逆にする必要があります。チームの方針を確認した上で実装してください。

電話番号・郵便番号のフォーマット統一

電話番号のハイフン除去

phone-normalize.js
/**
 * 電話番号からハイフン・スペースを除去し、数字のみにする
 * @param { string } str - 電話番号文字列
 * @returns { string } 正規化された電話番号
 */
const normalizePhone = (str) => {
  if (!str) return str;
  // 全角→半角変換後、数字以外を除去
  const halfWidth = str.replace(/[!-~]/g, (char) => {
    return String.fromCharCode(char.charCodeAt(0) - 0xFEE0);
  });
  return halfWidth.replace(/[^\d]/g, '');
};

郵便番号のフォーマット統一(ハイフン付き)

zipcode-normalize.js
/**
 * 郵便番号を「NNN-NNNN」形式に正規化する
 * @param { string } str - 郵便番号文字列
 * @returns { string } 正規化された郵便番号
 */
const normalizeZipCode = (str) => {
  if (!str) return str;

  // 全角→半角変換
  let normalized = str.replace(/[0-9]/g, (char) => {
    return String.fromCharCode(char.charCodeAt(0) - 0xFEE0);
  });

  // 数字のみ抽出
  const digits = normalized.replace(/[^\d]/g, '');

  // 7桁の場合はハイフン付きに整形
  if (digits.length === 7) {
    return `${digits.slice(0, 3)}-${digits.slice(3)}`;
  }

  return digits;
};

複数の正規化を組み合わせる

実務では複数の正規化処理を組み合わせて適用することが一般的です。正規化ルールをフィールドごとに定義する構成を紹介します。

combined-normalization.js
(() => {
  'use strict';

  // 正規化関数群
  const normalizers = {
    toHalfWidth: (str) => {
      if (!str) return str;
      return str.replace(/[!-~]/g, (c) =>
        String.fromCharCode(c.charCodeAt(0) - 0xFEE0)
      );
    },
    trim: (str) => {
      if (!str) return str;
      return str.replace(/^[\s\u3000]+|[\s\u3000]+$/g, '');
    },
    toHiragana: (str) => {
      if (!str) return str;
      return str.replace(/[\u30A1-\u30F6]/g, (c) =>
        String.fromCharCode(c.charCodeAt(0) - 0x60)
      );
    },
    normalizeZipCode: (str) => {
      if (!str) return str;
      const digits = str.replace(/[0-9]/g, (c) =>
        String.fromCharCode(c.charCodeAt(0) - 0xFEE0)
      ).replace(/[^\d]/g, '');
      return digits.length === 7 ? `${digits.slice(0, 3)}-${digits.slice(3)}` : digits;
    },
  };

  // フィールドごとの正規化ルール定義
  const FIELD_RULES = {
    '会社名': ['trim'],
    '担当者名': ['trim'],
    'フリガナ': ['trim', 'toHiragana'],
    'メールアドレス': ['trim', 'toHalfWidth'],
    '電話番号': ['trim', 'toHalfWidth'],
    '郵便番号': ['trim', 'normalizeZipCode'],
  };

  const events = [
    'app.record.create.submit',
    'app.record.edit.submit',
    'mobile.app.record.create.submit',
    'mobile.app.record.edit.submit',
  ];

  kintone.events.on(events, (event) => {
    const record = event.record;

    Object.entries(FIELD_RULES).forEach(([fieldCode, rules]) => {
      if (!record[fieldCode] || !record[fieldCode].value) return;

      let value = record[fieldCode].value;

      // ルールを順番に適用
      rules.forEach((ruleName) => {
        if (normalizers[ruleName]) {
          value = normalizers[ruleName](value);
        }
      });

      record[fieldCode].value = value;
    });

    return event;
  });
})();
チェック

正規化ルールをオブジェクトで管理すると、新しいフィールドや新しい正規化ルールの追加が容易です。また、ルール定義を見るだけでどのフィールドにどの正規化が適用されるかが一目で分かります。

まとめ

  • 全角→半角変換は charCodeAt0xFEE0 のオフセットで実現できる
  • \s\u3000 を組み合わせることで半角・全角スペースの両方をトリムできる
  • カタカナ→ひらがな変換は Unicode コードポイントの 0x60 オフセットで変換可能
  • 郵便番号や電話番号は、数字のみを抽出してからフォーマットを整形するのが確実
  • 正規化ルールをフィールドごとにオブジェクトで定義すると、保守性が高まる
  • 正規化処理は submit イベントで保存直前に適用するのが最も確実

関連記事

submit イベントのバリデーション
kintone の submit イベント(create.submit / edit.submit)を使って、レコードの保存前にカスタムバリデーションを実装する方法を解説します。フィールド単位のエラー表示、複数フィールドの相関チェック、非同
フィールド値の変更イベント
kintone JavaScript カスタマイズにおけるフィールド値変更イベント(app.record.create.change.フィールドコード)の使い方を解説します。ドロップダウン・ラジオボタン・チェックボックスなどの変更を検知し、
フィールドコードの命名
kintoneで作成できるアプリには様々なフィールドが存在し、その全てにフィールド名とフィールドコードを割り振る必要があります。フィールド名は主にユーザーが見える部分に、フィールドコードは主にアプリ管理者およびJavaScriptで参照する

練習問題

全角英数字を半角に変換するために使用するUnicodeのオフセット値はどれですか?

入力値の正規化処理を適用するタイミングとして、最も適切なイベントはどれですか?

#kintone #JavaScript #TypeScript