Преобразование двух символов ascii в их «соответствующее» односимвольное расширенное представление ascii

Проблема: у меня есть две строки фиксированной ширины из внешней системы. Первый содержит базовые символы (например, az), второй (МОЖЕТ) содержать диакритические знаки, которые должны быть добавлены к первой строке для создания фактических символов.

string asciibase = "Dutch has funny chars: a,e,u";
string diacrits  = "                       ' \" \"";

//no clue what to do

string result = "Dutch has funny chars: á,ë,ü";

Я мог бы написать массовый поиск и замену для всех символов + разные диакритические знаки, но надеялся на что-то более элегантное.

Кто-нибудь знает, как это исправить? Пробовал с вычислением десятичных значений, используя string.Normalize (С#), но безрезультатно. Кроме того, Google действительно ничего не нашел.


person Mark van Straten    schedule 09.03.2010    source источник
comment
Вы ищете противоположность string.Normalize, боюсь, нет встроенного метода, чтобы получить то, что вы хотите...   -  person Paolo Tedesco    schedule 09.03.2010
comment
Я думаю, что он после нормализации, просто его диакритические знаки не являются объединяющими символами, поэтому это не работает.   -  person    schedule 09.03.2010


Ответы (4)


Я не могу найти простого решения, кроме использования таблиц поиска:

public void TestMethod1()
{
    string asciibase = "Dutch has funny chars: a,e,u";
    string diacrits = "                       ' \" \"";
    var merged = DiacritMerger.Merge(asciibase, diacrits);
}

[EDIT: упрощенный код после предложений в ответах от @JonB и @Oliver]

public class DiacritMerger
{
    static readonly Dictionary<char, char> _lookup = new Dictionary<char, char>
                         {
                             {'\'', '\u0301'},
                             {'"', '\u0308'}
                         };

    public static string Merge(string asciiBase, string diacrits)
    {
        var combined = asciiBase.Zip(diacrits, (ascii, diacrit) => DiacritVersion(diacrit, ascii));
        return new string(combined.ToArray());
    }

    private static char DiacritVersion(char diacrit, char character)
    {
        char combine;
        return _lookup.TryGetValue(diacrit, out combine) ? new string(new [] {character, combine}).Normalize()[0] : character;
    }
}
person Mikael Svenson    schedule 09.03.2010

Преобразуйте диакритические знаки в подходящие значения Unicode из диапазона Unicode, объединяющего диакритические знаки:

http://www.unicode.org/charts/PDF/U0300.pdf

Затем соедините символ и его диакритический знак вместе, например. для e-острой U + 0065 = «e» и U + 0301 = острый.

  String s = "\u0065\u0301";

Потом:

  string normalisedString = s.Normalize();

Объединит два в новую строку.

person Community    schedule 09.03.2010

Проблема в том, что указанные диакритические знаки должны быть явно проанализированы, потому что двойные точки не существуют в единственном числе, и поэтому для этого случая используются двойные кавычки. Таким образом, для решения вашей проблемы у вас нет другого шанса реализовать каждый необходимый случай.

Вот отправная точка, чтобы получить ключ к разгадке...

    public SomeFunction()
    {
        string asciiChars = "Dutch has funny chars: a,e,u";
        string diacrits = "                       ' \" \"";

        var combinedChars = asciiChars.Zip(diacrits, (ascii, diacrit) =>
        {
            return CombineChars(ascii, diacrit);
        });

        var Result = new String(combinedChars.ToArray());
    }

    private char CombineChars(char ascii, char diacrit)
    {
        switch (diacrit)
        {
            case '"':
                return AddDoublePoints(ascii);
            case '\'':
                return AddAccent(ascii);
            default:
                return ascii;
        }
    }

    private char AddDoublePoints(char ascii)
    {
        switch (ascii)
        {
            case 'a':
                return 'ä';
            case 'o':
                return 'ö';
            case 'u':
                return 'ü';
            default:
                return ascii;
        }
    }

    private char AddAccent(char ascii)
    {
        switch (ascii)
        {
            case 'a':
                return 'á';
            case 'o':
                return 'ó';
            default:
                return ascii;
        }
    }
}

IEnumerable.Zip уже реализован в .Net 4, но чтобы получить его в версии 3.5, вам понадобится этот код (взято у Эрика Липперта):

public static class IEnumerableExtension
{
    public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>
        (this IEnumerable<TFirst> first,
        IEnumerable<TSecond> second,
        Func<TFirst, TSecond, TResult> resultSelector)
    {
        if (first == null) throw new ArgumentNullException("first");
        if (second == null) throw new ArgumentNullException("second");
        if (resultSelector == null) throw new ArgumentNullException("resultSelector");
        return ZipIterator(first, second, resultSelector);
    }

    private static IEnumerable<TResult> ZipIterator<TFirst, TSecond, TResult>
        (IEnumerable<TFirst> first,
        IEnumerable<TSecond> second,
        Func<TFirst, TSecond, TResult> resultSelector)
    {
        using (IEnumerator<TFirst> e1 = first.GetEnumerator())
        using (IEnumerator<TSecond> e2 = second.GetEnumerator())
            while (e1.MoveNext() && e2.MoveNext())
                yield return resultSelector(e1.Current, e2.Current);
    }
}
person Oliver    schedule 09.03.2010
comment
Решение, которое вы даете, было единственным простым выходом, который я нашел, но также и самым убивающим мозг ... Я держу его на крайний случай;) - person Mark van Straten; 09.03.2010
comment
Прочитав другие ответы, вы, возможно, найдете хорошее решение, объединив их все (как это сделал Микаэль в своем посте). - person Oliver; 10.03.2010

Я не знаком с C# или его стандартными библиотеками, но одним из альтернативных подходов может быть использование чего-то вроде существующего синтаксического анализатора/рендерера символов HTML/SGML/XML, или, если вы действительно собираетесь представить его в браузере, ничего!

Псевдокод:

for(i=0; i < strlen(either_string); i++) {
  if isspace(diacrits[i]) {
     output(asciibase[i]);
  }else{
     output("&");
     output(asciibase[i]);
     switch (diacrits[i]) {
       case '"' : output "uml"; break;
       case '^' : output "circ"; break;
       case '~' : output "tilde"; break;
       case 'o' : output "ring"; break;
       ... and so on for each "code" in the diacrits modifier
       ... (for acute, grave, cedil, lig, ...)
     }
     output(";");
  }
}

Таким образом, A + o -> &Aring;, u + " -> &uuml; и так далее.

Если вы сможете затем анализировать html-объекты, вы должны быть свободны дома и даже переносимы между кодировками!

person MattBianco    schedule 08.07.2010