サロゲートペア対応の文字列置換処理
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を基に、文字列を切り貼りする。