Oto dwa możliwe rozwiązania - jednowierszowy LINQ przetwarzający dane wejściowe od lewej do prawej i tradycyjny for
-loop przetwarzanie danych wejściowych od prawej do lewej. Który kierunek przetwarzania jest szybszy, zależy od długości łańcucha, dozwolonej długości bajtów oraz liczby i rozmieszczenia znaków wielobajtowych i trudno jest podać ogólną sugestię. Decyzja między LINQ a tradycyjnym kodem to chyba kwestia gustu (a może szybkości).
Jeśli szybkość ma znaczenie, można by pomyśleć o gromadzeniu długości każdego znaku w bajtach aż do osiągnięcia maksymalnej długości, zamiast obliczania długości całego ciągu w bajtach w każdej iteracji. Ale nie jestem pewien, czy to zadziała, ponieważ nie znam wystarczająco dobrze kodowania UTF-8. Teoretycznie mógłbym sobie wyobrazić, że długość łańcucha w bajtach nie jest równa sumie długości wszystkich znaków w bajtach.
public static String LimitByteLength(String input, Int32 maxLength)
{
return new String(input
.TakeWhile((c, i) =>
Encoding.UTF8.GetByteCount(input.Substring(0, i + 1)) <= maxLength)
.ToArray());
}
public static String LimitByteLength2(String input, Int32 maxLength)
{
for (Int32 i = input.Length - 1; i >= 0; i--)
{
if (Encoding.UTF8.GetByteCount(input.Substring(0, i + 1)) <= maxLength)
{
return input.Substring(0, i + 1);
}
}
return String.Empty;
}