如何快速检测是否空白字符

简介: 在Parser场景,包括SQL Parser和JSON Parser,如果更快检测空白字符时一个提升性能的关键点。笔者有多年SQL Parser和JSON Parser的经验,把我所知道的一些检测空白的方法分享给大家。## 1. 什么是空白字符如果采用json.org的标准,空白字符包括:```bash'\b' -- ASCII 8'\t' -- ASCII 9'\n' -- ASC

在Parser场景,包括SQL Parser和JSON Parser,如果更快检测空白字符时一个提升性能的关键点。笔者有多年SQL Parser和JSON Parser的经验,把我所知道的一些检测空白的方法分享给大家。

1. 什么是空白字符

如果采用json.org的标准,空白字符包括:

'\b' -- ASCII 8
'\t' -- ASCII 9
'\n' -- ASCII 10
'\f' -- ASCII 12
'\r' -- ASCII 13
' '  -- ASCII 32

2. 检测空白字符的5种方法

2.1 方法1

JDK的Character提供了isWhiteSpace方法,逻辑不能定制化,不支持上面的'\b'字符判空,但为了性能比较,也加入进来。

boolean space = Character.isWhitespace(ch);

2.1 方法2

这个常规办法,用6个并列的or判断。所有的字符检测都需要做6次判断,性能较差。

boolean space = ch == ' '
    || ch == '\n'
    || ch == '\r'
    || ch == '\f'
    || ch == '\t'
    || ch == '\b';

2.2 方法3

由于空白字符最大的是空格ASCII 32,在方法2的基础上先做一个预先检测,这样就能获得非常好的性能,但当输入的有大量空白字符\b时,就就会面临方法2的问题。fastjson 1.x ( http://github.com/alibaba/fastjson )判空用的是这个方法。

boolean space = ch <= ' '
    && (ch == ' '
        || ch == '\n'
        || ch == '\r'
        || ch == '\f'
        || ch == '\t'
        || ch == '\b');

2.3 方法4

这种算法,在JDK 17下性能有较大提升。在大量输入是非空字符时,性能并不出色。

boolean space;
switch (ch) {
    case ' ':
    case '\n':
    case '\r':
    case '\t':
    case '\b':
    case '\f':
        space = true;
        break;
    default:
        space = false;
        break;
}

2.4 方法5

通过预计算一个常量的long,然后做bitAnd判断。
fastjson2 ( https://github.com/alibaba/fastjson2 )判空用的是这个方法。

static final long SPACE = (1L << ' ') 
    | (1L << '\n') 
    | (1L << '\r') 
    | (1L << '\f') 
    | (1L << '\t') 
    | (1L << '\b');


boolean space = ch <= ' ' && ((1L << ch) & SPACE) != 0;

3. 测试环境

3.1 x86服务器

  • 使用阿里云x64当前代计算型4核8G服务器,CPU型号 Intel Xeon(Ice Lake) Platinum 8369B

3.2 ARM服务器

  • 使用阿里云ARM当前代计算型4核8G服务器,CPU型号 Ampere Altra / AltraMax

3.3 JDK

  • 下载Oracle最新的LTS版本Linux JDK
jdk1.8.0_333_x64
jdk-11.0.15.1_x64
jdk-17.0.3.1_x64
jdk1.8.0_333_aarch64
jdk-11.0.15.1_aarch64
jdk-17.0.3.1_aarch64

3.4 测试数据

{"images": [{
      "height":768,
      "size":"LARGE",
      "title":"Javaone Keynote",
      "uri":"http://javaone.com/keynote_large.jpg",
      "width":1024
    }, {
      "height":240,
      "size":"SMALL",
      "title":"Javaone Keynote",
      "uri":"http://javaone.com/keynote_small.jpg",
      "width":320
    }
  ],
  "media": {
    "bitrate":262144,
    "duration":18000000,
    "format":"video/mpg4",
    "height":480,
    "persons": [
      "Bill Gates",
      "Steve Jobs"
    ],
    "player":"JAVA",
    "size":58982400,
    "title":"Javaone Keynote",
    "uri":"http://javaone.com/keynote.mpg",
    "width":640
  }
}

4. JMH测试结果

4.1 x64测试结果

JDK8 JDK11 JDK17
方法1 1756.884 1692.215 1770.658
方法2 1911.820 1866.888 1903.105
方法3 3496.629 4228.972 3956.434
方法4 2798.679 2910.525 2876.148
方法5 3522.462 3694.007 4474.286
  • 原始数据
### jdk1.8.0_333_x64
Benchmark                                   Mode  Cnt     Score      Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5  1756.884 ?    2.202  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5  1911.820 ?    5.965  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  3496.629 ?  739.373  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  2798.679 ? 1024.227  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  3522.462 ?  859.084  ops/ms

### jdk-11.0.15.1_x64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5  1692.215 ? 363.925  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5  1866.888 ?  33.836  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  4228.972 ? 212.870  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  2910.525 ? 584.406  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  3694.007 ? 158.193  ops/ms


### jdk-17.0.3.1_x64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5  1770.658 ? 651.168  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5  1903.105 ?  40.520  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  3956.434 ? 628.745  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  2876.148 ? 127.401  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  4474.286 ? 539.261  ops/ms

4.1 ARM测试结果

JDK8 JDK11 JDK17
方法1 911.795 785.339 1269.834
方法2 789.439 833.830 842.177
方法3 2304.419 2429.907 2146.953
方法4 880.387 1124.967 1540.419
方法5 2363.957 2392.123 2570.536
  • 原始数据
### jdk1.8.0_333_aarch64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5   911.795 ?   5.171  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5   789.439 ? 163.867  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  2304.419 ?  29.643  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5   880.387 ?  63.411  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  2363.957 ? 759.335  ops/ms

### jdk-11.0.15.1_aarch64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5   785.339 ?   5.361  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5   833.830 ?  14.402  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  2429.907 ?   9.120  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  1124.967 ? 811.435  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  2392.123 ? 381.551  ops/ms

### jdk-17.0.3.1_aarch64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5  1269.834 ?   5.587  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5   842.177 ?   7.969  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  2146.953 ? 518.320  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  1540.419 ?  32.401  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  2570.536 ?   2.284  ops/ms

5. 结论

综合下来,无论是x64还是aarch64,方法5性能最理想。

相关文章
|
3月前
|
前端开发 JavaScript 安全
前端JS实现密码校验键盘横竖、26字母、相同字母、相同数字、密码包含用户名、数字 字母不能连续 不能相同三个、不能横向 竖向 连续三个 包含字符、不能有中文符号
该 JavaScript 代码实现了一个严格的密码校验功能,确保密码满足多种安全要求,包括长度、字符类型、不包含中文及特殊字符、不与用户名相似等。通过多个辅助函数,如 `validateFormat` 检查密码格式,`isHasChinaCharFun` 检测中文符号,`getCharAll` 生成键盘组合,以及 `checkPasswordFun` 综合验证密码的有效性和安全性。此工具对于提高用户账户的安全性非常有用。
100 0
|
4月前
|
C语言
输入一行字符
该C语言程序通过`getchar()`函数读取用户输入的字符,并使用`while`循环直到遇到换行符`\n`停止读取。程序统计并分类计数了输入中的英文字母、数字、空格及其他字符的数量,最后将统计结果输出。示例输出显示了对字符串&quot;www.runoob.com 123&quot;的正确统计结果。
50 4
|
8月前
输入一个字符,判断该字符是大写字母、小写字母,数字还是其他字符,并作相应的显示。
输入一个字符,判断该字符是大写字母、小写字母,数字还是其他字符,并作相应的显示。 提示:利用ord()函数来获得字符的 ASCIl。
180 1
输入一个字符,判断该字符是大写字母、小写字母,数字还是其他字符,并作相应的显示。
|
8月前
|
索引 Python
字符串:比较、拼接、切割、转义字符;相关切割、替换、查找、去除空白、转大小写函数的方法
字符串:比较、拼接、切割、转义字符;相关切割、替换、查找、去除空白、转大小写函数的方法
47 0
|
8月前
按要求输入字符
【2月更文挑战第5天】输入一些字符,逐个把它们送到磁盘上去,直到输入一个#为止。
48 0
从键盘任意输入一个字符,编程判断是否是字母(包括大小写)
从键盘任意输入一个字符,编程判断是否是字母(包括大小写)
541 0
从键盘任意输入一个字符,编程判断是否是字母(包括大小写)
|
图形学 C++
C/C++打造图像转字符工具(非常有趣)
C/C++打造图像转字符工具(非常有趣)
353 0
C/C++打造图像转字符工具(非常有趣)