我可以使用正则表达式或其他方法更快地执行此操作吗?

Posted

技术标签:

【中文标题】我可以使用正则表达式或其他方法更快地执行此操作吗?【英文标题】:Can I perform this operation faster with regex or something else? 【发布时间】:2013-02-22 10:12:39 【问题描述】:

我试图了解更多string operationsregexes。 例如,这是一个给定的 String 数组:

String [] tab = "__09_23_HELLO","__89_2_WORLD","900_23_TRY","_34_90_SATELLITE", 
"___23_", "390";

我在这里要做的是仅在下划线后跟一个字母后保留数据,如果找不到,请返回null。在这个例子中,我会得到这个:

HELLO WORLD TRY SATELLITE null null

所以我写了这个递归函数:

public String getName(String string, int i)

    if(i == string.length()-1) return null;
    if(string.charAt(i) != '_' || 
      (string.charAt(i) == '_' && !Character.isLetter(string.charAt(i+1)))) 
        return getName(string, i+1);
    else
        return string.substring(i+1);

而且效果很好。但由于我不知道很多正则表达式(也许还有其他方法?),我想知道我是否可以使用正则表达式来做到这一点,以及它是否会在处理大量数据时更快地进行。

感谢您的回答。

【问题讨论】:

【参考方案1】:

虽然您可以使用递归函数,但使用不同的方法肯定会更快:

要么我会使用循环(类似于您的方法,但使用循环而不是递归来增加计数器i)。

或者,按照您的建议使用正则表达式匹配来编写它。

这两种可能性中哪一种更快并不容易决定,但我猜想正则表达式更快,除非你的循环代码非常聪明并且尽可能少。要找出没有办法对这两种方法进行编码并对其进行基准测试...

【讨论】:

感谢您的回答。当我回复 jlordo 时,我担心每次进入 for 循环时都必须重新初始化 Matcher,如果我使用正则表达式,我是否错了? 我尝试迭代处理它,为每个 tab[i] 创建一个 j for 循环,但它比我的递归循环花费更多时间。 嗯,很有趣。想分享那个迭代代码吗?至于Matcher 初始化:很可能是初始化比较慢。特别是对于短字符串/简单模式(如您的情况),“手绘”版本可能是最快的。但与所有性能问题一样,唯一确定的方法是实施它并运行一些基准测试......【参考方案2】:

对数组中的每个元素应用正则表达式:

/[^_\d\s]+/g

【讨论】:

【参考方案3】:

JIT 很难优化递归调用(请参阅this article),所以我尽量避免它。这是一个正则表达式解决方案(结合子字符串,正如您对标签的预期)。

String [] tab = "__09_23_HELLO","__89_2_WORLD","900_23_TRY","_34_90_SATELLITE",  "___23_", "390";
Pattern pattern = Pattern.compile("_[a-zA-Z]");
for (int i = 0; i < tab.length; i++) 
    Matcher matcher = pattern.matcher(tab[i]);
    if (matcher.find()) 
        tab[i] = tab[i].substring(matcher.start() + 1);
     else 
        tab[i] = null;
    

System.out.println(Arrays.toString(tab));

【讨论】:

你的例子很有趣,非常感谢你的回答。但是假设我们每次进入 for 循环时都必须重新初始化匹配器,最终会不会更慢?它会改变一些东西以在 for 循环之前创建 Matcher matcher; 并且每次都重新初始化它:matcher = pattern.matcher(tab[i]); @Rob:必须为每个输入字符串重新初始化匹配器。如果在循环之后不使用匹配器,在循环之前放置Matcher matcher; 不会改变生成的字节码,因此具有相同的性能。几周前在另一个答案中验证了这一点。那是因为 Matcher matcher; 不会创建匹配器,但 pattern.matcher(tab[i]); 会。【参考方案4】:

我创建了以下实现(它转换原始字符串数组中的值):

for (int index = 0; index < strings.length; index++) 
    String eachString = strings[index];
    int startIndex = eachString.lastIndexOf('_') + 1;
    if (startIndex > 0 && eachString.length() != startIndex && Character.isLetter(eachString.charAt(startIndex))) 
        strings[index] = eachString.substring(startIndex);
     else 
        strings[index] = null;
    

return strings;

【讨论】:

以上是关于我可以使用正则表达式或其他方法更快地执行此操作吗?的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式匹配 MySQL 注释

加速此代码的提示

哪个更快?修剪()或正则表达式?

正则表达式:如何将 re.sub 与可变数量的元素一起使用?

有没有办法让 zip 或其他压缩文件更快地提取?

正则表达式之Python操作指南(re使用)