将两个ASCII字符转换为它们对应的一个字符扩展ASCII表示形式。

6
问题: 我从外部系统中获取到两个固定宽度的字符串。第一个字符串包含基本字符(如a-z),第二个字符串(可能)包含要附加到第一个字符串中以创建实际字符的变音符号。
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#)等方法,但都没有结果。同时,谷歌也没有提供有效的解决方案。


很抱歉,您正在寻找与string.Normalize相反的方法,但是我恐怕没有内置的方法可以得到您想要的内容... - Paolo Tedesco
我认为他想要进行规范化,只是他的变音符号不是组合字符,所以无法实现。 - user159335
4个回答

5

将变音符号从Unicode组合变音符号范围转换为适当的Unicode值:

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

然后将字符和它的变音符号结合在一起,例如对于e-acute,U+0065="e"且U+0301=acute。

  String s = "\u0065\u0301";

然后:

  string normalisedString = s.Normalize();

将两个内容合并为一个新的字符串。

1

问题是,指定的变音符号必须被明确地解析,因为独立的双点不存在,所以双引号用于此情况。所以为了解决您的问题,除了实现每个需要的情况之外,您没有其他选择。

这里有一个起点来获取线索...

    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);
    }
}

你提供的解决方案是我找到的唯一简单的出路,但也是最费脑筋的... 我会把它作为最后的手段保留;) - Mark van Straten
1
在阅读其他答案后,您可能会通过以某种方式结合它们中的所有内容(就像Mikael在他的帖子中所做的那样)找到一些好的解决方案。 - Oliver

1

除了使用查找表,我找不到简单的解决方案:

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;
    }
}

0

我不熟悉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实体,则应该可以自由地在各种字符集之间移植!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接