JavaScriptでバイト単位で文字列を切り取る方法

2022年10月25日火曜日

javascript

t f B! P L

スポンサーリンク

はじめに

古来からのシステムでは文字列は基本的に「Shift-JIS」で扱われており、アプリから出力するファイル形式も固定長と呼ばれる、項目間の区切り文字がなく、各項目は固定のバイト長になるように半角スペース等で埋められたファイルで保存されていました。そして、このようなシステムでは、文字列をバイト位置で切り取る処理が盛んに行われていました。

この記事では、古来からの伝統工法であるバイト単位での文字列切り取りを、JavaScriptで実装する方法を紹介します。

実装

全角かどうか判定する

文字列をバイト単位で切り取る場合、Shift-JIS換算で全角の場合は2バイト、半角文字の場合は1バイトとして数える。しかし、JavaScript内ではエンコード方式としてUTF-16が採用されているため、半角ですらも2バイト計算になる。

そこで、全角文字の判定は正規表現を使って半角の Unicode範囲でチェックする。

  /**
   * 全角文字かチェックします。
   * @param src チェック対象の文字列
   * @returns 全角文字の場合 true
   */
  static isFullWidth(src: string) {
    return (String(src).match(/[\x01-\x7E\uFF65-\uFF9F]/)) ? false : true;
  }

バイト単位で文字列を切り取る

次に、開始バイト位置、バイト数を指定して文字列をバイト単位で切り取る関数を作成する。
少しごちゃごちゃしたコードになっているが、上で作成した isFullWidth 関数を使って、全角文字の場合は2バイト、半角文字の場合は1バイト換算で文字列を切り取る関数になっている。

  /**
   * バイト単位で文字列切り取り
   * @param src 対象の文字列
   * @param start 開始バイト
   * @param size 切り取るバイト数
   * @returns バイト単位で切り取った文字列
   */
  static substrByte(src: string, start: number, size: number) {
    let result = ""
    let count1 = 0
    let count2 = 0

    for(let i = 0; i < src.length; i++) {
      const c = src.charAt(i)
      const char_size = isFullWidth(c) ? 2 : 1

      if (count1 >= start) {
        count2 += char_size
        if (count2 <= size) {
          result += c
        } else {
          break
        }  
      }
      count1 += char_size
    }

    return result
  }

バイト単位の文字列切り取りで注意が必要なのが、全角文字の途中に開始または終了位置を指定された場合の挙動である。

今回の関数では、開始位置に全角の途中の位置が指定された時は1文字後ろの文字から、終了位置に全角の途中の位置が指定された時は1文字手前の文字までを返す仕様になっている。


//2バイト目から4バイト切り取る
console.log( substrByte("あい1234", 2, 4) )   //=> い12

//1バイト目は全角の途中なので、3バイトから3バイト (4 - 1byte) 切り取る
console.log( substrByte("あい1234", 1, 4) )   //=> い12

//終了位置が全角の途中なので、1文字前までの文字列を切り取る
console.log( substrByte("あい1234", 0, 3) )   //=> い12

スポンサーリンク

まとめ

JavaScriptでバイト単位の文字列切り取りをするシーンは少ないと思うが、古来のシステム連携など、以外と役にときもきっとあるはず。

スポンサーリンク
スポンサーリンク

このブログを検索

Profile

自分の写真
Webアプリエンジニア。 日々新しい技術を追い求めてブログでアウトプットしています。
プロフィール画像は、猫村ゆゆこ様に書いてもらいました。

仕事募集もしていたり、していなかったり。

QooQ