我有一个多行字符串,由一组不同的分隔符分隔:

(Text1)(DelimiterA)(Text2)(DelimiterC)(Text3)(DelimiterB)(Text4)

我可以使用string将这个字符串分割成各个部分。分裂,但似乎我无法获得与分隔符正则表达式匹配的实际字符串。

换句话说,这就是我得到的结果:

Text1 Text2 Text3 Text4

这就是我想要的

Text1 DelimiterA Text2 DelimiterC Text3 DelimiterB Text4

JDK中是否有任何方法可以使用分隔符正则表达式分割字符串,但同时保留分隔符?


当前回答

我建议使用Pattern和Matcher,这几乎肯定会达到你想要的效果。你的正则表达式需要比你在String.split中使用的更复杂一些。

其他回答

传递第三个参数为“true”。它还将返回分隔符。

StringTokenizer(String str, String delimiters, true);

我不太懂Java,但如果你找不到一个Split方法,我建议你自己做一个。

string[] mySplit(string s,string delimiter)
{
    string[] result = s.Split(delimiter);
    for(int i=0;i<result.Length-1;i++)
    {
        result[i] += delimiter; //this one would add the delimiter to each items end except the last item, 
                    //you can modify it however you want
    }
}
string[] res = mySplit(myString,myDelimiter);

它不是很优雅,但也可以。

如果你想保留字符,那么使用split方法,该方法存在.split()方法中的漏洞。

请看这个例子:

public class SplitExample {


    public static void main(String[] args) {  
        String str = "Javathomettt";  
        System.out.println("method 1");
        System.out.println("Returning words:");  
        String[] arr = str.split("t", 40);  
        for (String w : arr) {  
            System.out.println(w+"t");  
        }  
        System.out.println("Split array length: "+arr.length);  
        System.out.println("method 2");
        System.out.println(str.replaceAll("t", "\n"+"t"));
    }

我喜欢StringTokenizer的想法,因为它是可枚举的。 但它也是过时的,可以用String代替。split返回一个单调的String[](并且不包括分隔符)。

所以我实现了一个StringTokenizerEx,它是一个Iterable,它接受一个真正的regexp来分割字符串。

一个真正的regexp意味着它不是一个重复的'字符序列'来形成分隔符: 'o'只匹配'o',并将'ooo'分成三个分隔符,其中有两个空字符串:

[o], '', [o], '', [o]

但是regexp o+在拆分“aooob”时将返回预期的结果

[], 'a', [ooo], 'b', []

使用StringTokenizerEx:

final StringTokenizerEx aStringTokenizerEx = new StringTokenizerEx("boo:and:foo", "o+");
final String firstDelimiter = aStringTokenizerEx.getDelimiter();
for(String aString: aStringTokenizerEx )
{
    // uses the split String detected and memorized in 'aString'
    final nextDelimiter = aStringTokenizerEx.getDelimiter();
}

该类的代码可以在DZone snippet中找到。

与通常的代码挑战响应(包含测试用例的自包含类)一样,复制粘贴它(在“src/test”目录中)并运行它。它的main()方法说明了不同的用法。


注:(2009年底编辑)

《Final Thoughts: Java Puzzler: Splitting hair》这篇文章很好地解释了String.split()中的奇怪行为。 乔希·布洛赫(Josh Bloch)甚至在回应那篇文章时评论道:

是的,这很痛苦。FWIW,这样做有一个很好的理由:与Perl的兼容性。 做这件事的人是Mike "madbot" McCloskey,他现在在谷歌和我们一起工作。Mike确保Java的正则表达式几乎通过了所有30K Perl正则表达式测试(并且运行得更快)。

谷歌公共库Guava还包含一个Splitter,它是:

使用更简单 由谷歌(而不是你)维护

所以它可能值得一看。从他们最初的粗略文件(pdf):

JDK有:

String[] pieces = "foo.bar".split("\\.");

如果你想要它所做的事情,使用它是很好的: -正则表达式 - result作为数组 -它处理空碎片的方式 小谜题:",a,,b,".split(",")返回…

(a) "", "a", "", "b", ""
(b) null, "a", null, "b", null
(c) "a", null, "b"
(d) "a", "b"
(e) None of the above

答案:(e)以上都不是。

",a,,b,".split(",")
returns
"", "a", "", "b"

只跳过尾随空!(谁知道防止跳过的变通方法?这是一个有趣的…) 在任何情况下,我们的Splitter都更加灵活:默认行为很简单:

Splitter.on(',').split(" foo, ,bar, quux,")
--> [" foo", " ", "bar", " quux", ""]

如果您想要额外的功能,请提出要求!

Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.split(" foo, ,bar, quux,")
--> ["foo", "bar", "quux"]

配置方法的顺序并不重要——在分割过程中,在检查空之前进行修整。

快速回答:使用非物理边界,如\b分割。我将尝试和实验,看看它是否有效(在PHP和JS中使用)。

这是可能的,也是一种工作,但可能会分裂太多。实际上,这取决于你想拆分的字符串和你需要的结果。提供更多细节,我们将更好地帮助您。

另一种方法是自己进行拆分,捕获分隔符(假设它是可变的),然后将其添加到结果中。

我的快速测试:

String str = "'ab','cd','eg'";
String[] stra = str.split("\\b");
for (String s : stra) System.out.print(s + "|");
System.out.println();

结果:

'|ab|','|cd|','|eg|'|

有点太多了……: -)