String#replaceAll():在环视中表示字符串的结尾或开头?

时间:2014-06-28 11:56:50

标签: java regex

我正在研究一个参数解析器,它将获取String[]个参数并将其转换为我正在使用的程序可用的输出。参数由空格分隔,因此在文本here are some arguments中,每个单词都是一个单独的参数。但是,我认为用户可能需要将单词组合在一起,所以我在单词的末尾以反斜杠的形式添加此功能。

此外,因为程序将参数作为映射读取并使用关键字来链接值(考虑命令行标志,如--password 123456,可以出现在命令中的任何位置),需要有一种方法逃避论证,为了保持一致性,我已经提出了\<arg>。这意味着去掉反斜杠的正则表达式应该忽略字符串开头的那些。

要考虑的另一件事是能够使用另一个反斜杠来转义分组反斜杠。这意味着不应删除任何跟随另一个反斜杠的反斜杠。例如,two\\ arguments成为一个以two\arguments为元素的数组。

最后,我想在未触及的单词中间留下反斜杠。这意味着正则表达式应该删除位于字符串末尾或后跟空格的反斜杠。

根据这些规则,

  • these\ are\ together将成为一个带有反斜杠的参数;
  • back\slash将保持不变;
  • \test\\将成为\test\;和
  • \test会保持不变。

我目前正在使用环视功能来达到我想要的效果:

String[] args = input.split("(?<!(?<!\\\\)\\\\) ");

for (int i = 0; i < args.length; ++i)
    args[i] = args[i].replaceAll("(?<!\\\\)\\\\(?= )", "");

最初,我使用表达式'(?<!(?<!\\)\\) '(没有撇号)拆分参数,从而处理分组。现在,解析器继续剥离反斜杠,这是上述表达式无法处理的任务。

这导致正则表达式(?<!\\)\\(?= )。通常,当在String#replaceAll("(?<!\\\\)\\\\(?= )", "")中使用此表达式时,可以实现一些想要的效果:

  • these\ are\ together变为these are together;和
  • back\slash保持原样。

但是,一旦在字符串的开头或结尾处发现反斜杠,此表达式就会出现问题。例如,\test\\被错误地解析为test\\,因为第一个反斜杠前面没有另一个反斜杠,最后一个反斜杠后面没有空格。在使用regular expression represent empty characterregex ignore start of stringregular expression escape if not preceded by anything等问题搜索Google几小时后(每个都无济于事),我决定来找你们帮忙。所以,这是我的问题:

是否可以在环视中表示字符串的结束和开头?(或者,空字符也可以。)

我已经尝试了^$\b字符,这样我的表达式就像(?<!(^|\b|\\))\\(?=($|\b| )),但这没有效果。 (我也尝试过像(?<!(|\\))\\(?=(| ))这样的空文字。)

非常感谢任何帮助。提前谢谢!

2 个答案:

答案 0 :(得分:1)

您无法在外观中使用$^,因为:

  • lookarounds正试图 断言我们可以在当前位置之前或之后匹配某些模式 ,同时:
  • $^并不是您可以匹配的东西,自己也只是断言断言我们在结束 (分别为: 开始 输入

因此,您甚至可以将它们视为简单的 lookarounds (?<=^)只是简写^(?=$)$

在您的情况下,您应该通过检查正则表达式中的附加条件\来处理\\$位于行尾的情况,该条件变为:

((?<!\\)\\(?= )|\\$)

...或者,作为 Java String((?<!\\\\)\\\\(?= )|\\\\$)

查看工作示例here on regex101

答案 1 :(得分:0)

最简单的解决方案是将所有\视为特殊字符,如Java中的字符串。通过这种方式创建\文字,您需要使用两个\\

现在不是找到要拆分的地方而是创建可以接受作为从

构建的标记字符串的规则
  • alphanumerics - 例如\\w
  • 两个反斜杠
  • 或带有空格的反斜杠

这种组合的模式可能看起来像

Pattern p = Pattern.compile("(\\w+|(\\\\){2}|\\\\\\s)+");

现在要“标准化”它,你只需要用一个反斜杠替换两个反斜杠并替换其余的反斜杠(单个反斜杠)。你可以用

来做
replaceAll("(\\\\)\\\\|\\\\", "$1")

这个正则表达式的想法是首先尝试找到两个反斜杠并将它们中的第一个放在第1组中,这样我们就可以用第一个反斜杠替换它们。由于已经匹配的反斜杠在同一次传递中无法再次找到(匹配),因此单个反斜杠必须是未转义的,我们想要摆脱它们。因为对于他们来说,只有来自replaceAll的正则表达式的右侧将被发现左侧将为空,这意味着组1中将没有匹配,因此$1将返回我们想要的空字符串(替换单\用空字符串)。

以下是此解决方案的示例

String data = "these\\ are\\ \\\\toge\\\\ther and these\\\\ \\not\\";
System.out.println("user input = "+data);
System.out.println("--------------");

Pattern p = Pattern.compile("(\\w+|(\\\\){2}|\\\\\\s)+");
//find only combination of letters or two backslashes or backslash and space
Matcher m = p.matcher(data);
while (m.find())
    System.out.println(m.group().replaceAll("(\\\\)\\\\|\\\\", "$1"));

输出:

user input = these\ are\ \\toge\\ther and these\\ \not\
--------------
these are \toge\ther
and
these\
not