使用Java中的regex格式化字符串

时间:2011-11-19 19:46:54

标签: java regex string

有没有什么办法可以使用正则表达式将字符串格式化为特定的模式,或者是stringbuilder + substring更快的方法?

例如,说一个电话号码 - > 1234567890作为输入

输出为> (123)456-7890

我在本文中看到了这一点:http://www.4guysfromrolla.com/webtech/031302-1.shtml但是给出的解释是在ASP中。我怎么用Java ???

6 个答案:

答案 0 :(得分:31)

声明

由于几个答案已经解决了字符串构建器等的更高效率,我想向您展示如何使用正则表达式完成它并解决使用此方法的好处。

一个REGEX解决方案

使用此匹配的正则表达式(类似于Alan Moore's expression):

(.{3})(.{3})(.{4})

允许您将10个字符精确匹配到3个组中,然后使用引用这些组的替换表达式,并添加其他字符:

($1) $2-$3

从而按照您的要求生成替换品。当然,它也会匹配标点符号和字母,这是使用\d(编码为Java字符串\\d)而不是.通配符的原因。

为何选择REGEX?

正则表达式方法对此类方法的潜在优势是对字符串操作的“逻辑”压缩。由于所有“逻辑”都可以压缩成一串字符而不是预编译的代码,因此正则表达式匹配和替换字符串可以存储在数据库中,以便系统的有经验的用户更容易地操作,更新或定制。这使得情况在几个层面上变得更加复杂,但为用户提供了更大的灵活性。

使用其他方法(字符串操作),更改格式化算法以使其生成(555)123-4567555.123.4567而不是指定的(555) 123-4567基本上不可能仅通过用户接口。使用正则表达式方法,修改就像将($1) $2-$3(在数据库或类似商店中)更改为$1.$2.$3($1)$2-$3一样简单。

如果你想修改你的系统以接受“更脏”的输入,这可能包括各种格式化尝试,例如555-123.4567并将它们重新格式化为一致的东西,那么就可以制作一个字符串操作算法能够做到这一点,并重新编译应用程序,以实现您的工作方式。然而,使用正则表达式解决方案,系统大修不是必需的 - 只需更改解析和替换表达式(对于初学者来说可能有点复杂,立即理解):

^\D*1?\D*([2-9])\D*(\d)\D*(\d)\D*(\d)\D*(\d)\D*(\d)\D*(\d)\D*(\d)\D*(\d)\D*(\d).*$
($1$2$3) $4$5$6-$7$8$9$10

这将允许程序能力的重大“升级”,如下面的重新格式化所示:

"Input"                       "Output"
----------------------------- --------------------------------
"1323-456-7890 540"           "(323) 456-7890"
"8648217634"                  "(864) 821-7634"
"453453453322"                "(453) 453-4533"
"@404-327-4532"               "(404) 327-4532"
"172830923423456"             "(728) 309-2342"
"jh345gjk26k65g3245"          "(345) 266-5324"
"jh3g24235h2g3j5h3"           "(324) 235-2353"
"12345678925x14"              "(234) 567-8925"
"+1 (322)485-9321"            "(322) 485-9321"
"804.555.1234"                "(804) 555-1234"
"08648217634"                 <no match or reformatting>

正如您所看到的,它对输入“格式化”非常“宽容”,并且知道在数字的开头应该忽略1并且0应该导致错误,因为它是无效 - 全部存储在单个字符串中。

问题归结为性能与定制潜力。字符串操作比正则表达式更快,但未来的增强自定义需要重新编译而不是简单地更改字符串。也就是说,有些东西不能很好地表达(或者甚至以上述变化的方式表达)以及正则表达式无法实现的一些东西。

TL; DR:

Regex允许将解析算法存储到一个相对较短的字符串中,该字符串可以轻松存储,以便可以在不重新编译的情况下进行修改。更简单,更集中的字符串操作函数更有效,并且有时可以比正则表达式更有效。关键是要了解应用程序的工具和要求,并使用最适合的情况。

答案 1 :(得分:14)

RE使用substring无法完成相同操作,或者更难以执行此操作。

在您的情况下,最好只使用StringBuilderinsert()

假设电话号码长度验证到位(= 10个字符)

        String phoneNumber = "1234567890";
        StringBuilder sb = new StringBuilder(phoneNumber)
                                .insert(0,"(")
                                .insert(4,")")
                                .insert(8,"-");
        String output = sb.toString();
        System.out.println(output);          

<强>输出

(123)456-7890

答案 2 :(得分:7)

相同的技术适用于Java;你只需要调整Java语法和API:

s = s.replaceFirst("(\\d{3})(\\d{3})(\\d{4})", "($1) $2-$3");
但是,我不明白你为什么要问更快的方法。你尝试过这样的事情并遇到性能问题吗?你几乎可以肯定用StringBuilder更有效地做到这一点,但实际上它几乎肯定不值得努力。

或者您是否正在谈论学习如何使用正则表达式实现此目的所需的时间相对于使用StringBuilder进行手动编码?不过,现在这是一个有争议的问题。 :d

答案 3 :(得分:2)

我会使用java String.format()方法和String.substring()

的组合

答案 4 :(得分:1)

带有groups的正则表达式匹配器除了大量的String容器外,还有很多RE匹配代码。 (您实际上可以查看源代码并亲自查看。)这不比使用substring()本身便宜,尤其是在您的情况下使用固定偏移量。

答案 5 :(得分:0)

带子字符串的StringBuilder会更快,但并不总是最简单/最好的方法。在这种情况下,我只会使用substring。

String num = "1234567890";
String formatted = "(" + num.substring(0,3) + ") "
     + num.substring(3,6) + "-" + num.substring(6);