如何匹配长与 Java 正则表达式?

Posted

技术标签:

【中文标题】如何匹配长与 Java 正则表达式?【英文标题】:How to match a long with Java regex? 【发布时间】:2012-06-29 21:19:08 【问题描述】:

我知道我可以用Pattern.compile("\\d*");匹配数字

但它不能处理较长的最小值/最大值。

对于与异常相关的性能问题,我不想尝试解析 long,除非它真的很长。

if ( LONG_PATTERN.matcher(timestampStr).matches() ) 
    long timeStamp = Long.parseLong(timestampStr);
    return new Date(timeStamp);
 else 
    LOGGER.error("Can't convert " + timestampStr + " to a Date because it is not a timestamp! -> ");
    return null;

我的意思是我不想要任何 try/catch 块,并且我不希望长时间引发异常,例如“564654954654464654654567879865132154778”,它超出了常规 Java long 的大小。

有人有一种模式来处理这种对原始 java 类型的需求吗? JDK是否提供了自动处理它的东西? Java 中是否存在故障安全解析机制?

谢谢


编辑:请假设“坏长字符串”不是例外情况。 我不是要一个基准,我来这里是为了一个代表 long 的正则表达式,仅此而已。 我知道正则表达式检查所需的额外时间,但至少我的长解析将始终保持不变,并且永远不会依赖于“坏长字符串”的百分比

我找不到链接了,但是 *** 上有一个很好的解析基准,它清楚地表明重用 sams 编译的正则表达式非常快,比抛出异常快很多,因此只有很小的异常阈值会造成系统比使用额外的正则表达式检查要慢。

【问题讨论】:

请注意,"\\d*" 也匹配空字符串。 可能是your question have already been asked。在我看来,异常会比正则表达式更快。 @Sorrow:很好理解前面的问题。重新例外与正则表达式:是什么让你这么认为?抛出异常不是一个快速的过程。编译后,正则表达式很快。 如我的回答中所述,这完全取决于例外情况发生的频率。使用模式匹配,您一直都在做额外的工作,除了异常,只有在引发异常时才会完成额外的工作。 我在这里同意@gexicide - 这完全取决于捕获异常的频率,因为无论如何都会检查正则表达式。在我看来,结合 T.J. Crowder 回答 (-?\\d1,19) 异常捕获应该是最佳的,那么。 【参考方案1】:

只需捕获 NumberFormatException,除非这种情况经常发生。

另一种方法是使用只允许长文字的模式。这种模式可能相当复杂。

第三种方法是首先将数字解析为 BigInt。然后你可以将它与 Long.MAX_VALUE 和 Long.MIN_VALUE 进行比较,以检查它是否在 long 的范围内。但是,这也可能代价高昂。

另请注意: 解析 long 非常快,这是一种非常优化的方法(例如,尝试在一个步骤中解析两个数字)。应用模式匹配可能比执行解析更昂贵。解析过程中唯一缓慢的是抛出 NumberFormatException。因此,如果异常情况不经常发生,那么简单地捕获异常是最好的方法

【讨论】:

OP 说:“对于与异常相关的性能问题,我不想尝试解析 long,除非它真的很长” 这个想法是为方法获得一个恒定的执行时间,而不是与错误长值的存在相关的执行时间。据我所知,我已经阅读了关于 SO 和正则表达式的基准,当不是每次都重新编译时,速度非常快 我正在阅读source code of parseLong,但是我没有找到任何可以解析两位数的证据。【参考方案2】:

long的最小值为-9,223,372,036,854,775,808,最大值为9,223,372,036,854,775,807。因此,最多 19 位数字。所以,\d1,19 应该可以让您到达那里,也许可以使用可选的-,并使用^$ 来匹配字符串的结尾。

所以大概

Pattern LONG_PATTERN = Pattern.compile("^-?\\d1,19$");

...或类似的东西,并假设您不允许逗号(或已经删除它们)。

正如 cmets 中的 gexicide 所指出的那样,上述允许的无效值范围很小(相比之下),例如 9,999,999,999,999,999,999。您可以使您的正则表达式变得更复杂,或者只是接受上述内容将清除绝大多数无效数字,从而减少您获得的解析异常的数量。

【讨论】:

不正确,您的模式允许数字 9,999,999,999,999,999,999 不在长期范围内 @gexicide:确实,可能需要进行一些调整。它至少会大大减少异常的数量。 当然,但我猜 OP 想要一个正确的解决方案。但我同意,该模式已经过滤了大多数不良情况。 谢谢,我也是这么想的->限制位数 你能解释一下“-”吗?我在 javadoc 模式中找不到这个【参考方案3】:

这个正则表达式应该做你需要的:

^(-9223372036854775808|0)$|^((-?)((?!0)\d1,18|[1-8]\d18|9[0-1]\d17|92[0-1]\d16|922[0-2]\d15|9223[0-2]\d14|92233[0-6]\d13|922337[0-1]\d12|92233720[0-2]\d10|922337203[0-5]\d9|9223372036[0-7]\d8|92233720368[0-4]\d7|922337203685[0-3]\d6|9223372036854[0-6]\d5|92233720368547[0-6]\d4|922337203685477[0-4]\d3|9223372036854775[0-7]\d2|922337203685477580[0-7]))$

但此正则表达式不会验证其他符号,例如 +L_ 等。如果您需要验证所有可能的 Long 值,则需要升级此正则表达式。

【讨论】:

以上是关于如何匹配长与 Java 正则表达式?的主要内容,如果未能解决你的问题,请参考以下文章

java 正则表达式 如何匹配固定长度的数字

Java中正则表达式如何实现从右往左匹配?

Java如何在正则表达式中匹配重复单词?

java中,正则表达式,如何过滤除数字和字母之外的其它字符??

Java 正则表达式:如何匹配 URL 路径?

Java 正则表达式 我想得到一个匹配结果 :给定一个字符串,匹配前三个字符为字母的任意一个字符串