我试图转换一些字符串,在法国加拿大,基本上,我想能够拿出法国重音标记在字母,同时保持字母。(例如,将é转换为e,那么crème brûlée就会变成creme brulee)

实现这一目标的最佳方法是什么?


当前回答

在这里弹出这个库,如果您还没有考虑过的话。看起来有一个完整的单元测试。

https://github.com/thomasgalliker/Diacritics.NET

其他回答

我没有使用过这种方法,但是Michael Kaplan在他的博客文章(有一个令人困惑的标题)中描述了一种方法,谈论剥离变音符:剥离是一项有趣的工作(又名剥离) 论无意义的意义,即一切 Mn字符是非空格的,但是 有些更非间距比 其他人)

static string RemoveDiacritics(string text) 
{
    var normalizedString = text.Normalize(NormalizationForm.FormD);
    var stringBuilder = new StringBuilder(capacity: normalizedString.Length);

    for (int i = 0; i < normalizedString.Length; i++)
    {
        char c = normalizedString[i];
        var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
        if (unicodeCategory != UnicodeCategory.NonSpacingMark)
        {
            stringBuilder.Append(c);
        }
    }

    return stringBuilder
        .ToString()
        .Normalize(NormalizationForm.FormC);
}

请注意,这是他之前帖子的后续:剥离变音符....

该方法使用String。Normalize将输入字符串分割为组成符号(基本上是将“基本”字符与变音符符分开),然后扫描结果并仅保留基本字符。这只是有点复杂,但实际上你看到的是一个复杂的问题。

当然,如果你限制自己使用法语,你可能会使用@David Dibben推荐的如何在c++ std::string中删除重音和波浪号的简单基于表的方法。

Imports System.Text
Imports System.Globalization

 Public Function DECODE(ByVal x As String) As String
        Dim sb As New StringBuilder
        For Each c As Char In x.Normalize(NormalizationForm.FormD).Where(Function(a) CharUnicodeInfo.GetUnicodeCategory(a) <> UnicodeCategory.NonSpacingMark)  
            sb.Append(c)
        Next
        Return sb.ToString()
    End Function

为了像最初的问题一样简单地删除法语加拿大重音标记,这里有一个使用正则表达式而不是硬编码转换和For/Next循环的替代方法。根据您的需要,它可以被压缩成一行代码;但是,我将它添加到一个扩展类中,以便于重用。

Visual Basic

Imports System.Text
Imports System.Text.RegularExpressions

Public MustInherit Class StringExtension
    Public Shared Function RemoveDiacritics(Text As String) As String
        Return New Regex("\p{Mn}", RegexOptions.Compiled).Replace(Text.Normalize(NormalizationForm.FormD), String.Empty)
    End Function
End Class

实现

    Private Shared Sub DoStuff()
        MsgBox(StringExtension.RemoveDiacritics(inputString))
    End Sub

c#

using System.Text;
using System.Text.RegularExpressions;

namespace YourApplication
{
    public abstract class StringExtension
    {
        public static string RemoveDiacritics(string Text)
        {
            return new Regex(@"\p{Mn}", RegexOptions.Compiled).Replace(Text.Normalize(NormalizationForm.FormD), string.Empty);
        }
    }
}

实现

        private static void DoStuff()
        {
            MessageBox.Show(StringExtension.RemoveDiacritics(inputString));
        }

Input: äáčďěéíľľňôóřŕšťúůýž ÄÁČĎĚÉÍĽĽŇÔŘŔŠŤÚŮÝŽ ÖÜË łŁđĐ țŢşŞçÇ øı

Output: aacdeeillnoorrstuuyz AACDEEILLNOORRSTUUYZ OUE łŁđĐ tTsScC øı

我加入了无法转换的字符,以帮助可视化接收到意外输入时会发生什么。

如果您还需要它来转换其他类型的字符,如波兰语的warsaw和Ł,那么根据您的需要,可以考虑合并这个答案(。NET Core友好),它使用CodePagesEncodingProvider到您的解决方案中。

如果有人感兴趣,我正在寻找类似的东西,最后写了如下:

public static string NormalizeStringForUrl(string name)
{
    String normalizedString = name.Normalize(NormalizationForm.FormD);
    StringBuilder stringBuilder = new StringBuilder();

    foreach (char c in normalizedString)
    {
        switch (CharUnicodeInfo.GetUnicodeCategory(c))
        {
            case UnicodeCategory.LowercaseLetter:
            case UnicodeCategory.UppercaseLetter:
            case UnicodeCategory.DecimalDigitNumber:
                stringBuilder.Append(c);
                break;
            case UnicodeCategory.SpaceSeparator:
            case UnicodeCategory.ConnectorPunctuation:
            case UnicodeCategory.DashPunctuation:
                stringBuilder.Append('_');
                break;
        }
    }
    string result = stringBuilder.ToString();
    return String.Join("_", result.Split(new char[] { '_' }
        , StringSplitOptions.RemoveEmptyEntries)); // remove duplicate underscores
}

公认的答案是完全正确的,但是现在,它应该更新为使用符文类而不是CharUnicodeInfo,因为c#和。net在最新版本中更新了分析字符串的方法(符文类已在。net Core 3.0中添加)。

下面的代码现在推荐用于。net 5+,因为它可以进一步用于非拉丁字符:

static string RemoveDiacritics(string text) 
{
    var normalizedString = text.Normalize(NormalizationForm.FormD);
    var stringBuilder = new StringBuilder();

    foreach (var c in normalizedString.EnumerateRunes())
    {
        var unicodeCategory = Rune.GetUnicodeCategory(c);
        if (unicodeCategory != UnicodeCategory.NonSpacingMark)
        {
            stringBuilder.Append(c);
        }
    }

    return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}