RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1271814
Accepted
aepot
aepot
Asked:2022-04-19 02:26:12 +0000 UTC2022-04-19 02:26:12 +0000 UTC 2022-04-19 02:26:12 +0000 UTC

Unicode 字符串规范化,去除了变音符号和其他变音符号

  • 772

有一项任务 - 组织搜索不同语言的单词文本。同时,所有可能的 Unicode 的变音符号和其他乐趣都可以出现在单词中。

例如,有 2 艘船的名称 - GermanGroßer Kurfürst和 Polish Błyskawica。我想在文本中写下grosser或blyska找到这些标题。为了让这一切成为可能,我们使用了文本规范化功能,该功能既适用于搜索字符串,也适用于文本本身。她将被进一步讨论。

有一个有效的、经过验证的、防弹的解决方案。

public static string NormalizeUnicode(string text)
{
    string stFormD = text.ToLower()
        .Replace('\u00A0', ' ') // неразрывный пробел
        .Replace("ß", "ss")
        .Replace('ł', 'l')
        .Normalize(NormalizationForm.FormD);
    StringBuilder sb = new StringBuilder(stFormD.Length);
    foreach (char c in stFormD) 
        if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) 
            sb.Append(c);
    return sb.ToString().Normalize(NormalizationForm.FormC);
}

输出将分别给出grosser kurfurst和blyskawica。唯一的问题是它甚至可以以可接受的速度工作,但我希望它更快。

自从使用该解决方案(在英文 Internet 上找到)以来,已经过去了很长时间,在此期间,.NET 5 出现了它的跨度和其他 C# 8-9 的乐趣。我试图优化。

检查代码

public static string NormalizeUnicodeNew(string text)
{
    ReadOnlySpan<char> stFormD = text.Normalize(NormalizationForm.FormD);
    StringBuilder sb = new StringBuilder(stFormD.Length);
    foreach (char c in stFormD)
    {
        switch (CharUnicodeInfo.GetUnicodeCategory(c))
        {
            case UnicodeCategory.UppercaseLetter:
                sb.Append(char.ToLower(c));
                break;
            case not UnicodeCategory.NonSpacingMark:
                if (c == 'ß')
                    sb.Append("ss");
                else
                    sb.Append(c switch
                    {
                        '\u00A0' => ' ',
                        'ł' => 'l',
                        _ => c
                    });
                break;
        }
    }
    return sb.ToString().Normalize(NormalizationForm.FormC);
}

测试代码

static void Main(string[] args)
{
    Console.OutputEncoding = Encoding.UTF8;
    string s = "Großer Kurfürst, Błyskawica";
    string text = string.Concat(Enumerable.Repeat(s, 1000000));
    Console.WriteLine(s);
    Console.WriteLine(NormalizeUnicode(s));

    Stopwatch sw = new Stopwatch();
    sw.Start();
    string n = NormalizeUnicode(text);
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);

    sw.Restart();
    string m = NormalizeUnicodeNew(text);
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);

    Console.WriteLine(m == n);
    Console.ReadKey();
}

发布版本的控制台输出

Großer Kurfürst, Błyskawica
grosser kurfurst, blyskawica
780
562
True

速度的提升真的很明显~15%,这已经是胜利了。我粗略地测量了时间,我还没有运行基准测试。

我想知道你的意见和建议,我还能在哪里调整。有一个想法可以使用string.Create,但它崩溃了,因为我不知道过滤后输出字符串会持续多长时间。

c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    aepot
    2022-04-21T07:12:56Z2022-04-21T07:12:56Z

    我做出了这个决定。

    public static string NormalizeUnicodeNew(string text)
    {
        ReadOnlySpan<char> stFormD = text.Normalize(NormalizationForm.FormD);
        int i = 0;
        Span<char> span = new char[stFormD.Length * 2];
        foreach (char c in stFormD)
        {
            UnicodeCategory category = CharUnicodeInfo.GetUnicodeCategory(c);
            if (category == UnicodeCategory.UppercaseLetter)
                span[i++] = char.ToLower(c);
            else if (category != UnicodeCategory.NonSpacingMark)
                span[i++] = c switch
                {
                    'ß' => span[i++] = 's',
                    '\u00A0' => ' ',
                    'ł' => 'l',
                    _ => c
                };
        }
        return new string(span[..i]).Normalize(NormalizationForm.FormC);
    }
    

    StringBuilder当然很快,但Span结果更快。与问题中的优化解决方案相比,性能提升了约 20%。

    在优化过程中,我发现

    • 协c switch { }变慢,例如
      sb.Append(c switch { 'a' => 'b', 'c' => "de" }).
    • if else if- 比switch (...) { }两个分支更快。
    • string.Concat(IEnumerable<char>)比 慢得多new string(IEnumerable<char>.ToArray()),但它并没有派上用场。:)
    • 1

相关问题

  • 使用嵌套类导出 xml 文件

  • 分层数据模板 [WPF]

  • 如何在 WPF 中为 ListView 手动创建列?

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    表格填充不起作用

    • 2 个回答
  • Marko Smith

    提示 50/50,有两个,其中一个是正确的

    • 1 个回答
  • Marko Smith

    在 PyQt5 中停止进程

    • 1 个回答
  • Marko Smith

    我的脚本不工作

    • 1 个回答
  • Marko Smith

    在文本文件中写入和读取列表

    • 2 个回答
  • Marko Smith

    如何像屏幕截图中那样并排排列这些块?

    • 1 个回答
  • Marko Smith

    确定文本文件中每一行的字符数

    • 2 个回答
  • Marko Smith

    将接口对象传递给 JAVA 构造函数

    • 1 个回答
  • Marko Smith

    正确更新数据库中的数据

    • 1 个回答
  • Marko Smith

    Python解析不是css

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5