1

フィールドの最大値が200バイトのみである入力システムを作成しています。私は以下を使用して残りのバイト数を数えています(この方法も議論の余地があるかもしれません!):

var totalBytes = 200;
var $newVal = $(this).val();
var m = encodeURIComponent($newVal).match(/%[89ABab]/g);
var bytesLeft = totalBytes - ($newVal.length + (m ? m.length : 0));

これはうまく機能しているように見えますが、誰かが大量のデータを貼り付ける場合は、入力をスライスして200バイトのみを表示できるようにしたいと思います。私は疑似コードで次のように見えると思います:

$newText = substrBytes($string, 0, 200);

任意のヘルプやガイダンスをいただければ幸いです。

編集:ここで起こっていることはすべてUTF-8です:)

編集2:私はすべてのキャラクターをループして評価できることを知っています。これを処理するためにもう少し優雅な何かがあるかもしれないと思っていたと思います。

ありがとう!

4

2 に答える 2

3

グーグル検索は、自分で試す入力ボックスを備えたブログ記事をもたらしました。SOはリンクよりも明確な回答が好きなので、ここでコードをコピーしていますが、クレジットはMcDowellにあります。

/**
 * codePoint - an integer containing a Unicode code point
 * return - the number of bytes required to store the code point in UTF-8
 */
function utf8Len(codePoint) {
  if(codePoint >= 0xD800 && codePoint <= 0xDFFF)
    throw new Error("Illegal argument: "+codePoint);
  if(codePoint < 0) throw new Error("Illegal argument: "+codePoint);
  if(codePoint <= 0x7F) return 1;
  if(codePoint <= 0x7FF) return 2;
  if(codePoint <= 0xFFFF) return 3;
  if(codePoint <= 0x1FFFFF) return 4;
  if(codePoint <= 0x3FFFFFF) return 5;
  if(codePoint <= 0x7FFFFFFF) return 6;
  throw new Error("Illegal argument: "+codePoint);
}

function isHighSurrogate(codeUnit) {
  return codeUnit >= 0xD800 && codeUnit <= 0xDBFF;
}

function isLowSurrogate(codeUnit) {
  return codeUnit >= 0xDC00 && codeUnit <= 0xDFFF;
}

/**
 * Transforms UTF-16 surrogate pairs to a code point.
 * See RFC2781
 */
function toCodepoint(highCodeUnit, lowCodeUnit) {
  if(!isHighSurrogate(highCodeUnit)) throw new Error("Illegal argument: "+highCodeUnit);
  if(!isLowSurrogate(lowCodeUnit)) throw new Error("Illegal argument: "+lowCodeUnit);
  highCodeUnit = (0x3FF & highCodeUnit) << 10;
  var u = highCodeUnit | (0x3FF & lowCodeUnit);
  return u + 0x10000;
}

/**
 * Counts the length in bytes of a string when encoded as UTF-8.
 * str - a string
 * return - the length as an integer
 */
function utf8ByteCount(str) {
  var count = 0;
  for(var i=0; i<str.length; i++) {
    var ch = str.charCodeAt(i);
    if(isHighSurrogate(ch)) {
      var high = ch;
      var low = str.charCodeAt(++i);
      count += utf8Len(toCodepoint(high, low));
    } else {
      count += utf8Len(ch);
    }
  }
  return count;
}
于 2012-04-18T12:03:22.197 に答える
1

JavaScriptの文字列は内部でUTF-16で表されるため、すべての文字は実際には2バイトを使用します。したがって、あなたの質問は「UTF-8でstrのバイト長を取得する」のようなものです。

シンボルの半分はほとんど必要ないので、198バイトまたは199バイトをカットする可能性があります。

これが2つの異なる解決策です:

// direct byte size counting
function cutInUTF8(str, n) {
    var len = Math.min(n, str.length);
    var i, cs, c = 0, bytes = 0;
    for (i = 0; i < len; i++) {
        c = str.charCodeAt(i);
        cs = 1;
        if (c >= 128) cs++;
        if (c >= 2048) cs++;
        if (c >= 0xD800 && c < 0xDC00) {
            c = str.charCodeAt(++i);
            if (c >= 0xDC00 && c < 0xE000) {
                cs++;
            } else {
                // you might actually want to throw an error
                i--;
            }
        }
        if (n < (bytes += cs)) break;
    }
    return str.substr(0, i);
}

// using internal functions, but is not very fast due to try/catch
function cutInUTF8(str, n) {
    var encoded = unescape(encodeURIComponent(str)).substr(0, n);
    while (true) {
        try {
            str = decodeURIComponent(escape(encoded));
            return str;
        } catch(e) {
            encoded = encoded.substr(0, encoded.length-1);
        }
    }
}
于 2012-04-18T12:04:28.747 に答える