2015-07-21 70 views
3

我想使用数字作为分隔符来分隔Java中的字符串,但保留数字。一些研究表明,使用String中的split方法()会很合适,但我不明白如何去做。为了进一步说明我的问题,我会用一个例子:在Java中分割字符串:可变长度的lookahead和lookbehead

Input: 20.55|50|0.5|20|20.55 

Required Output: ["20.55","|","50","|","0.5","|","20","|","20.55"] 

通过调用像我下面给出的例子split方法,无需先行和回顾后,我得到的输出我期待

expression.split("([0-9]+(\\.[0-9]+)?)") 

Output: ["|","|","|","|"] 

但是,如果我尝试这样做,以前瞻:

expression.split("(?=([0-9]+(\\.[0-9]+)?))") 

Output: ["2","0.","5","5|","5","0|","0.","5|","2","0|","2","0.","5","5"]  

并通过回顾后我得到一个异常:

线程“main”中的异常java.util.regex.PatternSyntaxException: Look-behind组在索引 附近没有明显的最大长度22(? < =([0-9] +([0-9] +)?))

任何人都可以解释我这种行为,并提出一个解决办法? PS:我知道我可以使用'|'打破字符串,但是这仅仅是一个愚蠢的例子,其实我需要一个更复杂的正则表达式...

编辑:

似乎是不可能做我想做什么,因为长度的分隔符。因为我正在寻找解决方案来解决一个较小的问题,我可以用它来练习其余的练习,我将重新翻译一下,看看是否有转机,就像第二个和第三个答案中找到的那样:

I想要打破包含算术表达式的Java中的字符串,并保留其所有项目。例如:

Input: 20.55 * 0.5 ** cos(360) + sin 0 * cos 90 + 1 * sin (180 + 90) * 0 
Output: ["20.55", "*", "0.5", "**", "cos", "(", "360", ")", "+", "sin", "0", "*", "cos", "90", "+", "1", "*", "sin", "(", "180", "+", "90", ")", "*", "0"] 

PSS:请注意,我必须使用'**'作为幂运算。

EDIT 2 继anubhava给出的答案,找到了解决办法,以打破其所有项目的算术表达式

Pattern p = Pattern.compile("\\*\\*|sin|cos|tan|\\d+(?:\\.\\d+)?|[-()+*/%]"); 
Matcher matcher = p.matcher(expression); 

while(matcher.find()) 
    System.out.println(matcher.group()); 
+0

要重新说明您的问题,是否正确地说要查找字符串中的所有数字?如果是这样,为什么不做一个正则表达式来查找数字而不是使用'split'? – MadConan

+0

不知道我是否理解你的问题......我需要用Java来完成。有没有另外一种方法在Java中使用正则表达式来完成它? – rsy

+0

使用'split'通常意味着你需要分隔符之间的东西。你可以做你正在问的问题,但我会用'Matcher'和'Matcher.find()'来获取数字。也许不是说这更好,更多“正常”。 – MadConan

回答

2

您可以使用此环视基于正则表达式分裂:

String[] toks = "20.55|50|0.5|20|20.55".split("(?=[^\\d.])|(?<=[^\\d.])"); 

for (String tok: toks) 
    System.out.printf("%s%n", tok); 

RegEx Demo


更新:

您可以使用此正则表达式匹配您的令牌:

Pattern p = Pattern.compile("sin|cos|tan|\\d+(?:\\.\d+)?|[-()+*/%]"); 

然后,您可以在while循环中使用Matcher#find()方法来获取所有匹配的标记。

+0

解决了给定的例子,但没有回答这个问题......我必须以同样的方式对待以下分隔符:“**”,“cos”,“sin”...什么'\ d'究竟是什么? – rsy

+1

'\ d'匹配'[0-9]'。你的编辑已经使这个问题**与以前完全不同。 'sin/cos/tan'等不是数字,而是反对之前提出的要求说**我想用Java作为分隔符来打破Java中的字符串** – anubhava

+1

现在检查我更新的正则表达式 – anubhava

1

的问题是,你不能定义长度可变lookbehinds。 +,*?全部匹配可变数量的字符。这是大多数正则表达式引擎的限制。

但是,您可以使用可变长度的lookahead。但在你的情况下,这不会做这项工作,因为周围不会消耗已经匹配的数据。

你想要的东西做:

([0-9]+(\\.[0-9]+)?)\\K 

什么\K不只是扔掉了已经匹配。因此,您仍然会被某些位置分割,并且不会重复浮动数字。

1

尝试:

(?<=\d)(?=\|)|(?<=\|)(?=\d) 

DEMO

在Java:

public class RegexTest{ 
    public static void main(String[] args){ 
     String string = "20.55|50|0.5|20|20.55"; 
     System.out.println(Arrays.toString(string.split("(?<=\\d)(?=\\|)|(?<=\\|)(?=\\d)"))); 
    } 
} 

与结果:

[20.55,|,50,|,0.5,| ,20,|,20.55]

编辑

要使用其他字符作为定界符包括 “*”, “赎罪” 等,你可以改变正则表达式来:

(?<=[0-9a-z*])(?=\|)|(?<=\|)(?=[0-9a-z*]) 

DEMO

哪里[0-9a-z*]表示数字,字母或“*”。如果你想包含其他字符,只需将其添加到字符类,如[0-9a-z*E]等。

+0

正如我回复@anubhava所说的那样,并不能完全回答这个问题,只是解决了给定的例子。 '\ d'究竟是什么,我怎么用它来解析其他的分隔符,比如“**”,“cos”,“sin”? – rsy

+0

@rsy'\ d'表示数字,如果您想要匹配其他字符,请认为提供示例,这非常重要 –

+0

通过使用此表达式:[^ \\ d。],您匹配的所有内容不是数字或者是一个点,在给定的例子中它和'|'的匹配相同。然后我会假设没有办法做我想做的事,并编辑原始问题 – rsy