如何在Java中使用某个分隔符拆分字符串但不删除该分隔符?

89

我在分割字符串时遇到问题。

我想用特定的分隔符将字符串拆分,但不想丢失该分隔符。

当我们在Java中使用 somestring.split(String separator) 方法来拆分字符串时,它会将字符串分成几部分,但会从字符串中删除分隔符。我不想让这种情况发生。

我希望得到以下结果:

String string1="Ram-sita-laxman";
String seperator="-";
string1.split(seperator);

输出:

[Ram, sita, laxman]

但我希望结果像下面这样:

[Ram, -sita, -laxman]
有没有一种方法可以获得像这样的输出?
5个回答

272
string1.split("(?=-)");

这段代码之所以能够运行,是因为split实际上使用了一个正则表达式。你看到的实际上是一个“零宽度正向预查”。
我很想多解释一些,但是我女儿想要玩茶会。:) 编辑:回来了!
为了解释这个问题,我首先会展示一个不同的split操作:
"Ram-sita-laxman".split("");

这将在每个零长度的字符串上分割您的字符串。在每个字符之间有一个零长度的字符串。因此,结果是:
["", "R", "a", "m", "-", "s", "i", "t", "a", "-", "l", "a", "x", "m", "a", "n"]

现在,我修改了我的正则表达式(""),只有当零长度字符串后面跟着一个破折号时才匹配。
"Ram-sita-laxman".split("(?=-)");
["Ram", "-sita", "-laxman"]

在这个例子中,?= 的意思是“向前查看”。更具体地说,它表示“正向查看”。为什么是“正向”的呢?因为你还可以有“负向”的向前查看(?!),它会在任何紧随着破折号的零长度字符串处分割:
"Ram-sita-laxman".split("(?!-)");
["", "R", "a", "m-", "s", "i", "t", "a-", "l", "a", "x", "m", "a", "n"]

你还可以使用正向预查 (?<=),它会在每个由连字符前导的零长度字符串处进行拆分:

"Ram-sita-laxman".split("(?<=-)");
["Ram-", "sita-", "laxman"]

最后,您还可以使用负向回顾后断言?<!),它将在每个长度为零的字符串上拆分,这些字符串不是以破折号开头:
"Ram-sita-laxman".split("(?<!-)");
["", "R", "a", "m", "-s", "i", "t", "a", "-l", "a", "x", "m", "a", "n"]

这四个表达式被称为“环视”表达式。
奖励:将它们组合在一起
我只是想展示一个最近遇到的例子,该例子结合了两个环视表达式。假设您希望将CapitalCase标识符拆分为其标记:
"MyAwesomeClass" => ["My", "Awesome", "Class"]

你可以使用以下正则表达式来完成这个任务:
"MyAwesomeClass".split("(?<=[a-z])(?=[A-Z])");

这个方法会在每个小写字母前面((?<=[a-z]))且在每个大写字母后面((?=[A-Z]))分割字符串,包括零长度的字符串。

这种技术也适用于驼峰式标识符。


7
+1:哇,从没想到正则表达式这么强大! - Rekin
2
+1 非常优雅的解决方案 - I82Much
2
你能举一个例子展示如何使用预查,将连字符前后都进行分隔吗?比如生成ram,-,sita,-,laxman - dwjohnston
5
与女儿共度茶会是解决世界面临的一个真实问题的美好方案。我支持这个答案。 - miir
2
哪些浏览器支持这个功能? "Ram-sita-laxman".split("(?<=-)"); 的结果是一个字符串 ["Ram-sita-laxman"] - AturSams
显示剩余10条评论

6

这个方法有些不可靠,但你可以使用replace函数引入一个虚拟分隔符。我不知道Java中的具体方法,但在C#中,可能是以下内容:

string1.Replace("-", "#-").Split("#");

当然,你需要选择一个在字符串中保证不会出现的虚拟分隔符。

1
危险的(即使我经常这样做 :-)) - Renaud
替换需要额外的时间,因此这种方法并不理想! - golkarm

3

Adam真是命中注定!我使用了他的答案来学习如何将文件对话框浏览器中的文件名文本插入到富文本框中。我遇到的问题是在文件字符串中添加一个新行时,连字符“\”被分割并删除了。使用Adam的代码混合后,我成功地在每个文件名中的“\”后创建了一个新行。

以下是我使用的代码:

OpenFileDialog fd = new OpenFileDialog();
        fd.Multiselect = true;
        fd.ShowDialog();

        foreach (string filename in fd.FileNames)
        {
            string currentfiles = uxFiles.Text;
            string value = "\r\n" + filename;

     //This line allows the Regex command to split after each \ in the filename. 

            string[] lines = Regex.Split(value, @"(?<=\\)");

            foreach (string line in lines)
            {
                uxFiles.Text = uxFiles.Text + line + "\r\n";
            }
        }

希望你能喜欢!

Walrusking


2
一种方法是将字符串分割,然后在每个提取的字符串(除第一个字符串外)的开头添加您的分隔符。

1
seperator="-";
String[] splitstrings = string1.split(seperator);
for(int i=1; i<splitstring.length;i++)
{
   splitstring[i] = seperator + splitstring[i];
}

这是适用于LadaRaider答案的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接