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

简介: 在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性能最理想。

相关文章
|
5月前
输入一个字符,判断该字符是大写字母、小写字母,数字还是其他字符,并作相应的显示。
输入一个字符,判断该字符是大写字母、小写字母,数字还是其他字符,并作相应的显示。 提示:利用ord()函数来获得字符的 ASCIl。
84 1
输入一个字符,判断该字符是大写字母、小写字母,数字还是其他字符,并作相应的显示。
|
5月前
|
索引 Python
字符串:比较、拼接、切割、转义字符;相关切割、替换、查找、去除空白、转大小写函数的方法
字符串:比较、拼接、切割、转义字符;相关切割、替换、查找、去除空白、转大小写函数的方法
31 0
解决“word空格后面下划线自动消失”问题
解决“word空格后面下划线自动消失”问题
|
机器学习/深度学习 移动开发 Unix
如何使用UE去除复制文本中的空格、换行符和TAB
如何使用UE去除复制文本中的空格、换行符和TAB
如何使用UE去除复制文本中的空格、换行符和TAB
从键盘任意输入一个字符,编程判断是否是字母(包括大小写)
从键盘任意输入一个字符,编程判断是否是字母(包括大小写)
450 0
从键盘任意输入一个字符,编程判断是否是字母(包括大小写)
去掉多余的空格---输入一个字符串,字符串中可能包含多个连续的空格,请将多余的空格去掉,只留下一个空格。输入格式
输入一个字符串,字符串中可能包含多个连续的空格,请将多余的空格去掉,只留下一个空格。 输入格式 共一行,包含一个字符串。 输出格式 输出去掉多余空格后的字符串,占一行。 数据范围 输入字符串的长度不超过 200200。 保证输入字符串的开头和结尾没有空格。
313 0
用#替换字符
给定一个由大小写字母构成的字符串。 把该字符串中特定的字符全部用字符 # 替换。
114 0