Looking for c# Keywords? Try Ask4Keywords

C# Language Правильное изменение строки


пример

В большинстве случаев, когда людям приходится менять строку, они делают это более или менее:

char[] a = s.ToCharArray();
System.Array.Reverse(a);
string r = new string(a);

Однако эти люди не понимают, что это на самом деле неправильно.
И я не имею ввиду из-за отсутствия проверки NULL.

Это на самом деле неправильно, потому что Glyph / GraphemeCluster может состоять из нескольких кодовых точек (например, символов).

Чтобы понять, почему это так, мы сначала должны знать о том, что на самом деле означает термин «характер».

Ссылка:

Характер - это перегруженный термин, чем может означать много вещей.

Кодовая точка - это атомная единица информации. Текст - это последовательность кодовых точек. Каждая кодовая точка - это номер, который задается стандартом Unicode.

Графема представляет собой последовательность из одной или нескольких кодовых точек, которые отображаются как единое графическое устройство, которое читатель распознает как один элемент системы письма. Например, и a, и ä являются графемами, но они могут состоять из нескольких кодовых точек (например, ä может быть двумя кодовыми точками, один для базового символа a, за которым следует один для diareis, но есть и альтернативный, устаревший, один код точка, представляющая эту графему). Некоторые кодовые точки никогда не являются частью какой-либо графемы (например, нулевой ширины без участия или переопределения направления).

Глиф представляет собой изображение, обычно хранящееся в шрифте (который представляет собой набор глифов), используемый для представления графемов или их частей. Шрифты могут составлять несколько глифов в одно представление, например, если вышеуказанная ä является одной кодовой точкой, шрифт может выбрать, чтобы отобразить это как два отдельных, пространственно перекрытых глифа. Для OTF таблицы GSUB и GPOS шрифта содержат информацию о замещении и позиционировании, чтобы сделать эту работу. Шрифт может содержать несколько альтернативных глифов для одной и той же графемы.

Таким образом, в C # символ на самом деле является CodePoint.

Это означает, что если вы просто отмените действительную строку, например Les Misérables , которая может выглядеть так

string s = "Les Mise\u0301rables";

как последовательность символов, вы получите:

selbaŕesiM seL

Как вы можете видеть, акцент делается на символе R вместо символа e.
Хотя string.reverse.reverse даст исходную строку, если вы оба раза измените массив символов, этот вид разворота определенно НЕ является обратным исходной строке.

Вам нужно только отменить каждый GraphemeCluster.
Итак, если все сделано правильно, вы можете изменить строку следующим образом:

    private static System.Collections.Generic.List<string> GraphemeClusters(string s)
    {
        System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>();

        System.Globalization.TextElementEnumerator enumerator = System.Globalization.StringInfo.GetTextElementEnumerator(s);
        while (enumerator.MoveNext())
        {
            ls.Add((string)enumerator.Current);
        }

        return ls;
    }


    // this 
    private static string ReverseGraphemeClusters(string s)
    {
        if(string.IsNullOrEmpty(s) || s.Length == 1)
             return s;
        
        System.Collections.Generic.List<string> ls = GraphemeClusters(s);
        ls.Reverse();

        return string.Join("", ls.ToArray());
    }

    public static void TestMe()
    {
        string s = "Les Mise\u0301rables";
        // s = "noël";
        string r = ReverseGraphemeClusters(s);

        // This would be wrong:
        // char[] a = s.ToCharArray();
        // System.Array.Reverse(a);
        // string r = new string(a);

        System.Console.WriteLine(r);
    }

И - о, радость - вы поймете, что если вы сделаете это правильно, это также будет работать для азиатских / южноазиатских / восточно-азиатских языков (и французского / шведского / норвежского и т. Д.) ...