特定の文字列にUnicode文字(特に2バイト文字)があるかどうかを確認する方法
-
02-07-2019 - |
質問
より正確に言うと、特定の文字列に2バイト文字が含まれているかどうかを確認できるかどうか(できればその方法を)知る必要があります。基本的に、ポップアップを開いて、中国語や日本語などの2バイト文字を含むテキストを表示する必要があります。この場合、英語やASCIIの場合よりもウィンドウサイズを調整する必要があります。 誰にも手がかりがありますか?
解決
JavaScriptは、Unicodeのかなり広範なサブセットをエンコードできるUCS-2としてテキストを内部的に保持します。
しかし、それはあなたの質問とはあまり関係ありません。 1つの解決策は、文字列をループして各位置の文字コードを調べることです。
function isDoubleByte(str) {
for (var i = 0, n = str.length; i < n; i++) {
if (str.charCodeAt( i ) > 255) { return true; }
}
return false;
}
これはあなたが望むほど速くないかもしれません。
他のヒント
これについてはミケサムエルの回答を使用しました。しかし、おそらくこの形式のために、 u
の前にエスケープスラッシュが1つだけあることに気付きました。これを正しく機能させるには、 \\ u
ではなく \ u
を使用します。
function containsNonLatinCodepoints(s) {
return /[^\u0000-\u00ff]/.test(s);
}
私のために働く:)
トップアンサーの2つの関数のベンチマークを行い、結果を共有すると思いました。私が使用したテストコードは次のとおりです。
const text1 = `The Chinese Wikipedia was established along with 12 other Wikipedias in May 2001. 中文維基百科的副標題是「海納百川,有容乃大」,這是中国的清朝政治家林则徐(1785年-1850年)於1839年為`;
const regex = /[^\u0000-\u00ff]/; // Small performance gain from pre-compiling the regex
function containsNonLatinCodepoints(s) {
return regex.test(s);
}
function isDoubleByte(str) {
for (var i = 0, n = str.length; i < n; i++) {
if (str.charCodeAt( i ) > 255) { return true; }
}
return false;
}
function benchmark(fn, str) {
let startTime = new Date();
for (let i = 0; i < 10000000; i++) {
fn(str);
}
let endTime = new Date();
return endTime.getTime() - startTime.getTime();
}
console.info('isDoubleByte => ' + benchmark(isDoubleByte, text1));
console.info('containsNonLatinCodepoints => ' + benchmark(containsNonLatinCodepoints, text1));
これを実行すると、次のようになりました:
isDoubleByte => 2421
containsNonLatinCodepoints => 868
したがって、この特定の文字列の正規表現ソリューションは約3倍高速です。
ただし、最初の文字がユニコードである文字列の場合、 isDoubleByte()
はすぐに返されるため、正規表現(依然として正規表現のオーバーヘッドがある)よりもはるかに高速です。
たとえば、文字列&#20013;&#22269;
の場合、次の結果が得られました。
isDoubleByte => 51
containsNonLatinCodepoints => 288
両方の世界を最大限に活用するには、おそらく両方を組み合わせた方が良いでしょう:
var regex = /[^\u0000-\u00ff]/; // Small performance gain from pre-compiling the regex
function containsDoubleByte(str) {
if (!str.length) return false;
if (str.charCodeAt(0) > 255) return true;
return regex.test(str);
}
その場合、最初の文字が中国語(テキスト全体が中国語である可能性が高い)の場合、関数は高速ですぐに戻ります。そうでない場合は、正規表現を実行します。これは、各文字を個別にチェックするよりも高速です。
実際には、少なくともJavascriptエンジンの観点から見ると、すべての文字はUnicodeです。
残念ながら、特定のUnicode範囲内の文字が存在するだけでは、より多くのスペースが必要であると判断するのに十分ではありません。 ASCII範囲をはるかに超えるUnicodeコードポイントを持つ他の文字とほぼ同じ量のスペースを占める文字がいくつかあります。活版印刷の引用符、発音区別記号付きの文字、特定の句読点記号、およびさまざまな通貨記号は、低ASCIIの範囲外であり、Unicodeの基本的な多言語プレーンのまったく異なる場所に割り当てられます。
一般的に、私が取り組んでいるプロジェクトは、すべての言語に余分なスペースを提供するか、JavaScriptを使用して、自動スクロールバーのCSS属性を持つウィンドウに、スクロールバーをトリガーする高さのコンテンツがあるかどうかを判断することを選択します。
CJK文字の存在または数を検出することで、少し余分なスペースが必要であると判断できる場合は、次の範囲を使用して正規表現を作成できます。 [\ u3300- \ u9fff \ uf900- \ ufaff]、およびそれを使用して、一致する文字数のカウントを抽出します。 (これは少し過度に粗く、BMP以外のすべてのケースを見逃し、おそらく他の関連する範囲を除外し、おそらく無関係な文字を含む可能性が高いですが、それが出発点です)。
繰り返しますが、本当に必要なのはGDIのMeasureString(または他のテキストレンダリングエンジンに相当するもの)であるため、フルテキストレンダリングエンジンのラインに沿って何もせずに大まかなヒューリスティックのみを管理できるようになります。私がそうしてからしばらく経ちましたが、最も近いHTML / DOMの同等物はdivに幅を設定し、高さを要求することです(切り取りと貼り付けの再利用、これにエラーがある場合はおpびします):
o = document.getElementById("test");
document.defaultView.getComputedStyle(o,"").getPropertyValue("height"))
ベンチマークテストは次のとおりです。 http://jsben.ch/NKjKd
これははるかに高速です:
function containsNonLatinCodepoints(s) {
return /[^\u0000-\u00ff]/.test(s);
}
これより:
function isDoubleByte(str) {
for (var i = 0, n = str.length; i < n; i++) {
if (str.charCodeAt( i ) > 255) { return true; }
}
return false;
}
実行時の高さ/幅に基づいてウィンドウのサイズを変更できないのはなぜですか?
ポップアップで次のようなものを実行します:
window.resizeTo(document.body.clientWidth, document.body.clientHeight);