gpt4 book ai didi

java - 从 Java 字符串中去除所有不可打印字符的最快方法

转载 作者:行者123 更新时间:2023-12-02 10:50:35 24 4
gpt4 key购买 nike

String 中去除所有不可打印字符的最快方法是什么?在 java ?

到目前为止,我已经尝试并测量了 138 字节、131 个字符的字符串:

  • 字符串 replaceAll() - 最慢的方法
  • 517009 结果/秒
  • 预编译一个 Pattern,然后使用 Matcher 的 replaceAll()
  • 637836 结果/秒
  • 使用 StringBuffer,使用 codepointAt() 获取代码点一一并附加到 StringBuffer
  • 711946 结果/秒
  • 使用 StringBuffer,使用 charAt() 获取字符一一并附加到 StringBuffer
  • 1052964 结果/秒
  • 预分配一个 char[]缓冲区,使用 charAt() 获取字符一一填充这个缓冲区,然后转换回字符串
  • 2022653 结果/秒
  • 预分配 2 char[]缓冲区 - 旧的和新的,使用 getChars() 一次获取现有字符串的所有字符,逐一迭代旧缓冲区并填充新缓冲区,然后将新缓冲区转换为字符串 - 我自己最快的版本
  • 2502502 结果/秒
  • 有 2 个缓冲区的相同内容 - 仅使用 byte[] , getBytes()并将编码指定为“utf-8”
  • 857485 结果/秒
  • 与 2 相同的东西 byte[]缓冲区,但将编码指定为常量 Charset.forName("utf-8")
  • 791076 结果/秒
  • 与 2 相同的东西 byte[]缓冲区,但将编码指定为 1 字节本地编码(这几乎是一件明智的事情)
  • 370164 结果/秒

  • 我最好的尝试如下:
        char[] oldChars = new char[s.length()];
    s.getChars(0, s.length(), oldChars, 0);
    char[] newChars = new char[s.length()];
    int newLen = 0;
    for (int j = 0; j < s.length(); j++) {
    char ch = oldChars[j];
    if (ch >= ' ') {
    newChars[newLen] = ch;
    newLen++;
    }
    }
    s = new String(newChars, 0, newLen);

    关于如何使其更快的任何想法?

    回答一个非常奇怪的问题的奖励积分:为什么直接使用“utf-8”字符集名称比使用预先分配的静态常量产生更好的性能 Charset.forName("utf-8") ?

    更新
  • 棘轮怪胎的建议产生了令人印象深刻的 3105590 个结果/秒的性能,提高了 +24%!
  • Ed Staub 的建议又带来了另一项改进 - 3471017 个结果/秒,比之前的最佳结果高出 12%。

  • 更新 2

    我已尽力收集所有建议的解决方案及其交叉突变并将其发布为 small benchmarking framework at github .目前它支持 17 种算法。其中之一是“特殊” - Voo1 算法( provided by SO user Voo )采用复杂的反射技巧从而实现了出色的速度,但它会扰乱 JVM 字符串的状态,因此单独进行基准测试。

    欢迎您检查并运行它以确定您的盒子上的结果。这是我对自己的结果的总结。它的规范:
  • Debian sid
  • Linux 2.6.39-2-amd64 (x86_64)
  • 从包安装的 Java sun-java6-jdk-6.24-1 , JVM 将自己标识为
  • Java(TM) SE 运行时环境(版本 1.6.0_24-b07)
  • Java HotSpot(TM) 64 位服务器 VM(构建 19.1-b02,混合模式)

  • 给定不同的输入数据集,不同的算法最终会显示出不同的结果。我在 3 种模式下运行了一个基准测试:

    同一个字符串

    此模式适用于 StringSource 提供的相同单个字符串类作为常量。摊牌是:

    ops/s │ 算法
    ──────────┼────────────────────────────────
    6 535 947 │ Voo1
    ──────────┼────────────────────────────────
    5 350 454 │ RatchetFreak2EdStaub1GreyCat1
    5 249 343 │ EdStaub1
    5 002 501 │ EdStaub1GreyCat1
    4 859 086 │ ArrayOfCharFromStringCharAt
    4 295 532 │ RatchetFreak1
    4 045 307 │ ArrayOfCharFromArrayOfChar
    2 790 178 │ RatchetFreak2EdStaub1GreyCat2
    2 583 311 │ RatchetFreak2
    1 274 859 │ StringBuilderChar
    1 138 174 │ StringBuilderCodePoint
    994 727 │ ArrayOfByteUTF8String
    918 611 │ ArrayOfByteUTF8Const
    756 086 │ MatcherReplace
    598 945 │ StringReplaceAll
    460 045 │ ArrayOfByteWindows1251

    以图表形式:
    Same single string chart
    (来源: greycat.ru)

    多个字符串,100%的字符串包含控制字符

    源字符串提供程序使用 (0..127) 字符集预先生成大量随机字符串 - 因此几乎所有字符串都包含至少一个控制字符。算法以循环方式从这个预先生成的数组中接收字符串。

    ops/s │ 算法
    ──────────┼────────────────────────────────
    2 123 142 │ Voo1
    ──────────┼────────────────────────────────
    1 782 214 │ EdStaub1
    1 776 199 │ EdStaub1GreyCat1
    1 694 628 │ ArrayOfCharFromStringCharAt
    1 481 481 │ ArrayOfCharFromArrayOfChar
    1 460 067 │ RatchetFreak2EdStaub1GreyCat1
    1 43​​8 435 │ RatchetFreak2EdStaub1GreyCat2
    1 366 494 │ RatchetFreak2
    1 349 710 │ RatchetFreak1
    893 176 │ ArrayOfByteUTF8String
    817 127 │ ArrayOfByteUTF8Const
    第778章 089
    734 754 │ StringBuilderCodePoint
    377 829 │ ArrayOfByteWindows1251
    224 140 │ MatcherReplace
    211 104 │ StringReplaceAll

    以图表形式:
    Multiple strings, 100% concentration
    (来源: greycat.ru)

    多个字符串,1%的字符串包含控制字符

    与之前相同,但只有 1% 的字符串是使用控制字符生成的 - 其他 99% 是使用 [32..127] 字符集生成的,因此它们根本不能包含控制字符。在我这里,这种合成负载最接近该算法的实际应用。

    ops/s │ 算法
    ──────────┼────────────────────────────────
    3 711 952 │ Voo1
    ──────────┼────────────────────────────────
    2 851 440 │ EdStaub1GreyCat1
    2 455 796 │ EdStaub1
    2 426 007 │ ArrayOfCharFromStringCharAt
    2 347 969 │ RatchetFreak2EdStaub1GreyCat2
    2 242 152 │ RatchetFreak1
    2 171 553 │ ArrayOfCharFromArrayOfChar
    1 922 707 │ RatchetFreak2EdStaub1GreyCat1
    1 857 010 │ RatchetFreak2
    1 023 751 │ ArrayOfByteUTF8String
    939 055 │ StringBuilderChar
    907 194 │ ArrayOfByteUTF8Const
    841 963 │ StringBuilderCodePoint
    606 465 │ MatcherReplace
    501 555 │ StringReplaceAll
    381 185 │ ArrayOfByteWindows1251

    以图表形式:
    Multiple strings, 1% concentration
    (来源: greycat.ru)

    我很难决定谁提供了最好的答案,但鉴于现实世界的应用程序最佳解决方案是由 Ed Staub 提供/启发的,我想标记他的答案是公平的。感谢所有参与其中的人,您的意见非常有帮助且非常宝贵。随意在您的机器上运行测试套件并提出更好的解决方案(工作 JNI 解决方案,有人吗?)。

    引用文献
  • GitHub repository带有基准测试套件
  • 最佳答案

    如果将此方法嵌入到不跨线程共享的类中是合理的,那么您可以重用缓冲区:

    char [] oldChars = new char[5];

    String stripControlChars(String s)
    {
    final int inputLen = s.length();
    if ( oldChars.length < inputLen )
    {
    oldChars = new char[inputLen];
    }
    s.getChars(0, inputLen, oldChars, 0);

    等等...

    这是一个巨大的胜利 - 20% 左右,据我了解目前的最佳情况。

    如果这要用于潜在的大字符串并且内存“泄漏”是一个问题,则可以使用弱引用。

    关于java - 从 Java 字符串中去除所有不可打印字符的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7161534/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com