从字符串中删除所有空格但保留一个换行符

9
我有一个包含制表符、空格和换行符的输入字符串:
        That      is a test.              
    seems to work       pretty good? working.








    Another test  again.

[编辑]: 我应该提供字符串以进行更好的测试,因为stackoverflow会删除所有特殊字符(制表符等)

String testContent = "\n\t\n\t\t\t\n\t\t\tDas      ist ein Test.\t\t\t  \n\tsoweit scheint das \t\tganze zu? funktionieren.\n\n\n\n\t\t\n\t\t\n\t\t\t      \n\t\t\t      \n    \t\t\t\n    \tNoch ein  Test.\n    \t\n    \t\n    \t";

我想达到这种状态:
That is a test.
seems to work pretty good? working.
Another test again.

String expectedOutput = "Das ist ein Test.\nsoweit scheint das ganze zu? funktionieren.\nNoch ein Test.\n";

任何想法?这可以通过使用正则表达式实现吗? replaceAll("\\s+", " ")不是我要寻找的。如果这个正则表达式能够保留现有的一个换行符,那就完美了。
我已经尝试过这种方法,但这对我来说似乎不太优秀。
BufferedReader bufReader = new BufferedReader(new StringReader(testContent));
String line = null;
StringBuilder newString = new StringBuilder();
while ((line = bufReader.readLine()) != null) {
    String temp = line.replaceAll("\\s+", " ");
    if (!temp.trim().equals("")) {
        newString.append(temp.trim());
        newString.append("\n");
    }
}

我认为你必须为此编写一些逻辑。你需要在一个空格后搜索非空格字符,并在换行后搜索非空格字符。 - Daniel Robertus
你想要的逻辑是什么?将连续的空格修剪为一个空格吗? - Black Maggie
@BlackMaggie 是的,我想那就是总结了。 - friesoft
@zvzdhk 不行,因为这样不能删除制表符并且不能将所有换行符折叠成单个换行符。 - friesoft
5个回答

15

使用一个正则表达式(加上一个小的制表符补丁):

input.replaceAll("^\\s+|\\s+$|\\s*(\n)\\s*|(\\s)\\s*", "$1$2")
     .replace("\t"," ");

虽然看起来正则表达式很可怕,但实际上可以分解为以下部分,并进行OR操作:

  • ^\s+ – 匹配开头的空格;
  • \s+$ – 匹配结尾的空格;
  • \s*(\n)\s* – 匹配包含换行符的空格,并捕获该换行符;
  • (\s)\s* – 匹配第一个空格字符并捕获之。

结果将得到两个捕获组的匹配,但同时只能有一个捕获组非空。这使我可以使用"$1$2"替换匹配,表示" 连接两个捕获组 "。

唯一剩下的问题是无法使用这种方法用空格替换制表符,因此我通过简单的非正则字符替换来解决这个问题。


6

四个步骤:

text
    // 1. compress all non-newline whitespaces to single space
    .replaceAll("[\\s&&[^\\n]]+", " ")
    // 2. remove spaces from begining or end of lines
    .replaceAll("(?m)^\\s|\\s$", "")
    // 3. compress multiple newlines to single newlines
    .replaceAll("\\n+", "\n")
    // 4. remove newlines from begining or end of string
    .replaceAll("^\n|\n$", "") 

我的解决方案唯一的问题是:如果行末有任何空格,则会留下单个空格;如果字符串有任何尾随换行符,则会留下单个换行符。我刚刚修复了它(最后希望如此:)) - MBO

2
如果我理解正确,您只想用一个换行符替换一连串的换行符。因此,使用适当的标志将\n\n*替换为\n。如果行中有很多空格,请先删除空格(^\s\s*$与多行模式),然后再替换换行符。
编辑: 这里唯一的问题是可能会有一些换行符残留在这里和那里,因此您必须小心地首先折叠空格,然后解决空行问题。您可以将其进一步简化为单个正则表达式,但使用这三个更容易阅读:
 Pattern spaces = Pattern.compile("[\t ]+");
 Pattern emptyLines = Pattern.compile("^\\s+$?", Pattern.MULTILINE);
 Pattern newlines = Pattern.compile("\\s*\\n+");
 System.out.print(
      newlines.matcher(emptyLines.matcher(spaces.matcher(
        input).replaceAll(" ")).replaceAll("")).replaceAll("\n"));

这在我的情况下也可以正常工作 :) 必须尝试更多的测试数据 - friesoft

2

为什么不这样做

String[] lines = split(s,"\n")
String[] noExtraSpaces = removeSpacesInEachLine(lines)
String result = join(noExtraSpaces,"\n")

不要忘记 Jamie Zawinski有关正则表达式的名言

。它意味着当你试图用正则表达式解决一个问题时,你最终可能会得到两个问题。


那么 "xx\n \n\n yy" 呢? - Marko Topolnik
@MarkoTopolnik 嗯,这取决于您是否需要保留空行或删除它们。 - denis.solonenko
@denis.solonenko 对不起,stackoverflow移除了所有特殊字符并将其转换为空格。因此,我只添加了包含所有特殊字符的字符串。 - friesoft

2

首先将所有的换行符替换为一个换行符,然后替换空格但不包括换行符,最后,您应该从字符串开头删除所有空白字符:

String test = "      This is              a real\n\n\n\n\n\n\n\n\n test !!\n\n\n   bye";
test = test.replaceAll("\n+", "\n");
test = test.replaceAll("((?!\n+)\\s+)", " ");
test = test.replaceAll("((?!\n+)\\s+)", "");

输出:

This is a real
test !!
bye

@MarounMaroun 对我来说,它会删除所有空格。我刚刚添加了包含正确转义字符的示例字符串。 - friesoft

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