サロゲートペア対応の文字列置換処理
entitiesをツイートに埋め込む際、entitiesに含まれるindicesを利用して文字列を置換する必要があるが、indicesには見た目の文字数が設定されている為、サロゲートペアの文字を含むtweetを扱うにあたってはJavaScriptやC#の文字列methodをそのまま使用すると問題が発生する。
仕方ないので、文字数で指定した部分の文字列を置換するmethodを自前で実装する事にする。
JavaScriptの場合:
function replace(text, start, end, part){ var offset = 0; var delta = start < end ? end - start : start - end; for(; offset < text.length; ++offset) { if(!start) break; var ch = text.charCodeAt(offset); if(ch >= 0xd800 && ch < 0xdc00) ++offset; --start; } start = offset; for(; offset < text.length; ++offset) { if(!delta) break; var ch = text.charCodeAt(offset); if(ch >= 0xd800 && ch < 0xdc00) ++offset; --delta; } end = offset; var left = text.substring(0, start); var right = text.substring(end); return left + part + right; }
C#の場合:
/// <summary> /// サロゲートペア対応文字列置換 /// </summary> /// <param name="text">置換対象の文字列を含む文字列</param> /// <param name="start">置換対象の文字列の開始位置</param> /// <param name="end">置換対象の文字列の終了位置</param> /// <param name="part">新しく埋め込む文字列</param> private string Replace(string text, int start, int end, string part) { int offset = 0; int delta = start < end ? end - start : start - end; for (; offset < text.Length; ++offset) { if (start == 0) break; if (Char.IsHighSurrogate(text[offset])) ++offset; --start; } start = offset; for (; offset < text.Length; ++offset) { if (delta == 0) break; if (Char.IsHighSurrogate(text[offset])) ++offset; --delta; } delta = offset - start; return text.Remove(start, delta).Insert(start, part); }
基本的に行う事は一緒で、対象文字列を一文字ずつ文字コードを確認して、サロゲートペアの1文字目が見つかったら2文字目を読み飛ばしつつ文字数をカウントする。 あとは算出したoffsetを基に、文字列を切り貼りする。