Java中的原始字符串-特别是用于正则表达式。多行字符串


74

有没有办法在Java中使用原始字符串(没有转义序列)?

(我正在编写大量的正则表达式代码,而原始字符串会使我的代码更具可读性)

我了解该语言不会直接提供此功能,但是有什么方法可以以任何方式“模拟”它们吗?


5
哦,我要那么多。多行字符串也是如此。也许是简单的插值。
Thilo

3
尽管您不会这样-我认为这只是鼓励您将数据与代码混合。关于REGEX的最好的地方是它们是数据,因此可以将其提取到某种形式的索引表中,从而简化了所有其他代码。信息的更改不需要重新编译,只需让客户编辑REGEX源文件即可。对于几乎所有我认为用于多行字符串的东西来说,都是如此。.总是更好的外部条件(如果没有别的,请考虑一下i18n!)
Bill K

ps。当我年轻的时候,一个聪明的程序员推论说,代码中内联的唯一常量应该是0和1,而那些仅用于循环终止/比较的情况几乎不再有效(我们可以使用foreach代替for(0 .. ))我当时以为他是疯子,但是我学得越好,理论听起来就越聪明。
比尔K

请注意(2018年1月),Java可能会使用原始字符串文字(JDK 10或更高版本):请参见在Java中,是否有一种无需转义引号就能编写字符串文字的方法?
VonC

情况发生了变化,如今标记为正确的答案是错误的。弗拉德给出了正确的答案。关于文本块。请考虑更改,因为此决定会使人们感到困惑。

Answers:


6

文字块进入Java

Java 13提供了期待已久的多行字符串

一些历史: Raw String Literals撤回。该功能原本打算作为JDK 12中的预览语言功能,但已撤消且未出现在JDK 12中。 它已由JDK 13中的Text Blocks(JEP 355)取代。

您可以使用文本块轻松定义多行字符串文字。您不需要添加常规String文字附带的视觉混乱:串联运算符和转义序列。您还可以控制如何格式化字符串值。例如,让我们看一下以下HTML代码段:

String html = """
<HTML>
  <BODY>
    <H1>"Java 13 is here!"</H1>
  </BODY>
</HTML>""";

注意,三个引号界定了块的开始和结束。


49

如果您使用的是Eclipse,这是一种解决方法。当您将文本粘贴到字符串文字中时,可以自动使长文本块正确地多行显示,并自动转义特殊字符

“-在这里粘贴-”;

如果在窗口→首选项→java→编辑器→键入→“粘贴到字符串文字中时转义文本”中启用该选项


6
这太棒了。希望我早点了解此功能!
aglassman

1
在Netbeans中也可以使用。
贾斯汀


29

我使用Pattern.quote。并且它解决了问题的问题。因此:

Pattern pattern = Pattern.compile(Pattern.quote("\r\n?|\n"));

quote方法返回一个与提供的string参数匹配的字符串,该返回字符串是本例中正确引用的字符串。


4
请注意,如果转义字符不是Java字符串文字的有效转义序列,但对正则表达式有效,则此方法将无效,例如:"\."
ygormutti 2015年

6
那很聪明,但是.... aaaaargh。对于现代语言中应该没有的问题,这是一个多么棘手的解决方案。根据ygormutti的观察,我什至不确定是否值得。
凯尔·斯特兰德

@KyleStrand这不是一个hacky解决方案。Pattern.quote即使Java具有原始字符串文字,也将需要使用:Java字符串文字中的像.+不需要任何特殊处理的字符,但仍需要对正则表达式进行转义。Python支持原始字符串文字,但仍具有re.escape
Alex Shesterov '18

1
@AlexShesterov正则表达式中转义的特殊字符仍然传递给正则表达式引擎的正则表达式的一部分。也就是说,正则表达式引擎接收文字\*序列。Java中缺少原始字符串,这使得创建带有将特殊字符视为文字的正则表达式模式的概念和创建带有特殊字符的字符串数据的概念相形见flat。这些是独立的概念
凯尔·斯特兰德

无论如何,这解决了我的问题:现在foo("\\[")可以很foo("[")开心了。
下雨

13

不(非常遗憾)。


1
这是我所见的关于SO的第一个答案,仅通过利用Java程序员xD的情感就获得了很多好评
varun


4

属性文件是常见的,但是很凌乱-我将大多数正则表达式都视为代码,并将其保存在我可以引用的位置,您也应该这样做。至于实际问题:)

是的,有一些方法可以解决可读性差的问题。您可以尝试:

String s = "crazy escaped garbage"; //readable version//

尽管在更新时需要小心。Eclipse有一个选项,允许您在引号之间粘贴文本,并为您应用转义序列。策略是先编辑可读版本,然后删除垃圾,并将其粘贴在空引号“”之间。


提示时间:

修改您的编辑器以进行转换;作为插件发布。我到处检查了插件,但没有找到(尽管尝试搜索)。转义的源字符串和文本框文本之间存在一一对应的关系(折价\ n,\ r \ n)。也许可以使用在结尾处带有两个引号的突出显示的文本。

String s = "##########
#####";

其中#是任何字符,突出显示-换行符被视为换行符。在突出显示区域中键入或粘贴的文本在“真实”源中进行转义,并显示为好像不是。(与Eclipse转义粘贴文本的方式相同,这将转义键入的文本,并在显示时不带反斜杠。)如果要正常编辑,请删除其中的引号引起语法错误。嗯


3

注意:截至今天为止,尚不可用。每当功能发布时,我可能都会再次编辑此答案。

正在进行中的建议是在Java中引入Raw Strings。在正则表达式的情况下,它们实际上很有用。

示例1:编码为的正则表达式字符串

  System.out.println("this".matches("\\w\\w\\w\\w"));

可以交替编码为

System.out.println("this".matches(`\w\w\w\w`));

因为反斜杠不被解释为具有特殊含义。

例2:多行带外语的String文字追加。

A multiple line string that was coded as 
    String html = "<html>\n" +
                "    <body>\n" +
                "         <p>Hello World.</p>\n" +
                "    </body>\n" +
                "</html>\n";

可以交替编码为

 String html = `<html>
                       <body>
                           <p>Hello World.</p>
                       </body>
                   </html>
                  `;

这避免了中间引号,串联和显式换行符的需要。

希望我们能尽快发布。


2
看起来这可能使它进入Java 12:dzone.com/articles/…–
JimmyJames,

@JimmyJames希望在人类文明消亡之前,或者至少在Python 2消亡之前,Java 12将成为主流…….. -_-
varun

2

String#getBytes()公开包含在每个单个String对象中的内部字节数组的副本,该对象实际上包含16位UTF-16编码的String-字节数组将包含转换为与平台的默认字符集匹配的相同字符串。我的意思是,我认为这与Java中的字符串几乎一样。


您应该将getBytes()与charsetName一起使用,字符串的编码可能与平台的编码不同
Rich Seller

任何体面的IDE都有一个属性文件编辑器,可以处理所有讨厌的转义。如Elicpse
托尔比约恩Ravn的安德森

Rich Seller:根据javadocs,它应该与平台默认字符集匹配,但是如果不匹配,我也不会感到惊讶。
埃斯科(Esko)

1

您可以编写自己的非转义属性读取器,然后将字符串放入资源文件中。


1

我个人认为正则表达式是字符串数据,而不是代码,因此我在代码中不喜欢它们-但我意识到这是不切实际且不受欢迎的(是的,我知道,您不必大吼大叫我)。

鉴于没有自然的方式可以做到这一点,我可以提出两种可能性(嗯,三种,但是第三种是,不自然的)。

因此,我个人的喜好是将文件解析为字符串。您可以命名文件中的每个条目,并将它们全部加载到哈希表中,以便从代码轻松访问。

第二选择,创建一个文件,该文件将被预处理为Java接口;这样做可以逃脱正则表达式。我个人不喜欢代码生成,但是如果java文件是100%从未人为编辑的,那还算不错(真正的邪恶是生成了您希望编辑的文件!)

第三(有点棘手,可能是个坏主意):您可能能够创建一个自定义doclet,该doclet会在编译时将注释中的字符串提取到文本文件或头文件中,然后使用上述两种其他方法之一。这样会将您的字符串保存在使用它们的同一文件中。要做到这一点真的很难,而且失败的代价是极高的,因此,除非我有压倒性的需求和一些相当出色的才能,否则我什至不会考虑。

我之所以只建议这样做,是因为注释是自由格式的,并且“ pre”标记中的内容对于格式化程序和其他系统丑陋的对象来说是非常安全的。doclet可以在打印javadocs之前将其提取出来,甚至可以添加一些生成的javadocs来表明您使用了正则表达式字符串。

在拒绝投票并告诉我这是一个愚蠢的想法之前-我知道,我只是想建议这样做,因为它很有趣,但是如上所述,我的偏好是一个简单的文本文件...


5
我见过的大多数正则表达式绝对是使用它们的程序的组成部分,不应视为数据。您不希望比那里的任何其他逻辑多或少地对其进行外部化,例如if语句中的条件。
Thilo

实际上,外部化条件通常也很好,这就是关闭背后的原因。正则表达式不是通常与外部数据绑定吗?如果是这样,您当然希望能够更改它们。我想说的是,您应该将一切都可以外部化,而regex的最大优点就是可以。
比尔K 2009年

1
我和Thilo在一起。正则表达式通常定义了特定代码正在寻找或分析该数据的数据类型。如果您将其外部化,我发现有人很容易在不意识到其含义的情况下进行更改。
凯文·布洛克

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.