解析字符串Groovy最有效的方法?

时间:2018-03-21 19:09:42

标签: groovy

在Groovy中解析以下字符串的最有效方法是什么?

 slt-5.16.1.0XYZ

这样我获得了以下结果:

 slt-5.16

值5和16可以是1-nnn。

帮助永远赞赏。

1 个答案:

答案 0 :(得分:2)

我建议在这种情况下使用一个简单的regex但是因为你已经提出了最有效的方法,我尝试了几种方法。

<强> TL; DR

使用substring()和几个嵌套indexOf()

input.substring(0, input.indexOf('.', input.indexOf('.') + 1 ) )

长篇故事(已更新)

我使用 Tim Yates 的好建议更新了基准测试,还添加了一些有趣的变体。您可以在下面找到结果,一些注意事项以及用于生成它们的代码:

Environment
===========
* Groovy: 2.4.14
* JVM: OpenJDK 64-Bit Server VM (25.71-b00, Oracle Corporation)
    * JRE: 1.8.0-internal
    * Total Memory: 117 MB
    * Maximum Memory: 1710.5 MB
* OS: Linux (4.13.0-37-generic, amd64)

Options
=======
* Warm Up: Auto (- 60 sec)
* CPU Time Measurement: On

                                               user  system    cpu   real

indexOf                                         329       0    329    330
regex, just not a dot                           704       7    711    722
manual loop, int vars                           885       0    885    896
tokenizeJoin                                   1074       0   1074   1079
manual loop, int vars and def i                1078       0   1078   1090
manual loop, Integer vars                      1065       3   1068   1085
manual loop, def vars                          1122       0   1122   1127
regex, restricting to number                   2725      24   2749   2760
manual loop, int vars but index without type  33087       0  33087  33132
manual loop, without types                    47600     286  47886  47944

一些简短的考虑因素:

  • 带有否定组的正则表达式(实际上排名第二)比限制组(低4倍)的正则表达式

  • 手动循环很快就像我期望的那样,如果你使用静态类型:int是最快的。 Integer速度较慢且与def相当。离开它们没有任何类型是最慢的解决方案!

代码:

@Grab('org.gperfutils:gbench:0.4.3-groovy-2.4')

def input  = 'slt-5.16.1.0XYZ'
def target = 'slt-5.16'

benchmark {
    'indexOf' {
        assert target == input.substring(0,
                           input.indexOf('.', input.indexOf('.') + 1)
                         )
    }
    'regex, just not a dot' {
        assert input.find(/^[^.]+[.][^.]+/) == target
    }
    'manual loop, int vars' {
        int index, counter = 0 
        for (int i=0; i <input.size(); i++) {
            if (input[i] == '.') { counter++ }
            if (counter == 2) { index = i; break }
        }
        assert input.substring(0,index) == target
    }
    'tokenizeJoin' {
        assert input.tokenize('.').take(2).join('.') == target
    }
    'manual loop, int vars and def i' {
        int index, counter = 0 
        for (def i=0; i <input.size(); i++) {
            if (input[i] == '.') { counter++ }
            if (counter == 2) { index = i; break }
        }
        assert input.substring(0,index) == target
    }
    'manual loop, Integer vars' {
        Integer index, counter = 0 
        for (Integer i=0; i <input.size(); i++) {
            if (input[i] == '.') { counter++ }
            if (counter == 2) { index = i; break }
        }
        assert input.substring(0,index) == target
    }
    'manual loop, def vars' {
        def index, counter = 0
        for (def i=0; i <input.size(); i++) {
            if (input[i] == '.') { counter++ }
            if (counter == 2) { index = i; break }
        }
        assert input.substring(0,index) == target
    }
    'regex, restricting to numbers' {
        assert (input =~ /(.+-\d+\.\d+)/)[0][1] == target 
    }
    'manual loop, int vars but index without type' {
        int index, counter = 0 
        for (i=0; i <input.size(); i++) {
            if (input[i] == '.') { counter++ }
            if (counter == 2) { index = i; break }
        }
        assert input.substring(0,index) == target
    }
    'manual loop, without types' {
        counter = 0
        for (i=0; i <input.size(); i++) {
            if (input[i] == '.') { counter++ }
            if (counter == 2) { index = i; break }
        }
        assert input.substring(0,index) == target
    }
}.prettyPrint()