Преобразование двух символов 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 (C#), но без результатов. Кроме того, Google действительно не появился с чем-то.
4 ответа
Я не могу найти простое решение, кроме как использовать таблицы поиска:
public void TestMethod1()
{
string asciibase = "Dutch has funny chars: a,e,u";
string diacrits = " ' \" \"";
var merged = DiacritMerger.Merge(asciibase, diacrits);
}
[РЕДАКТИРОВАТЬ: упрощенный код после предложений в ответах от @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;
}
}
Преобразуйте диакритические знаки в подходящие значения Unicode из диапазона Unicode, объединяющего диакритические метки:
http://www.unicode.org/charts/PDF/U0300.pdf
Затем шлепните полукокса и его диакритический знак, например, для e-острого, U+0065 = "e" и U+0301 = острый.
String s = "\u0065\u0301";
Затем:
string normalisedString = s.Normalize();
Объединит два в новую строку.
Проблема заключается в том, что указанные диакритические знаки должны быть явно проанализированы, потому что двойные точки не существуют как единичные, и поэтому в этом случае используются двойные кавычки. Таким образом, чтобы решить вашу проблему, у вас нет другого шанса, кроме как реализовать каждый необходимый случай.
Вот отправная точка, чтобы получить подсказку...
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, вам понадобится следующий код ( взято из Eric Lippert):
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);
}
}
Я не знаю 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
-> Å
, u + "
-> ü
и так далее.
Если тогда вы сможете анализировать html-объекты, вы должны быть дома свободными и даже переносимыми между кодировками!