1. 概述

在文本处理和分析中,移除字符串中的标点符号是一个常见的操作。

在这个简短的教程中,我们将探讨如何轻松地从给定字符串中删除标点符号。

2. 问题介绍

假设我们有一个字符串:

static final String INPUT = "It's 1 W o r d (!@#$%^&*{}[];':\")<>,.";

我们可以看到,字符串 INPUT 包含数字、字母、空格以及各种标点符号。

我们的目标是从字符串中只移除标点符号,保留字母、数字和空格在结果中

static final String EXPECTED = "Its 1 W o r d ";

在这个教程中,我们将主要使用Java标准库提供的String.replaceAll()方法来解决这个问题。为了简化,我们将使用单元测试断言来验证结果是否符合预期。

接下来,让我们看看如何移除这些标点符号。

3. 使用正则表达式模式“*[^\sa-zA-Z0-9]”和“\p{Punct}*

我们提到使用String.replaceAll()方法从输入字符串中移除标点符号。replaceAll()方法基于正则表达式进行字符串替换。它会检查输入字符串,并将所有匹配我们正则表达式模式的部分替换为替换字符串。

因此,正则表达式模式是解决这个问题的关键。

由于我们希望保留字母、数字和空格在结果中,我们可以将任何非数字、非字母或非空格字符替换为空字符串。我们可以使用正则表达式的字符范围[^\\sa-zA-Z0-9]来匹配这些字符。

接下来,让我们创建一个测试来检查是否有效:

String result = INPUT.replaceAll("[^\\sa-zA-Z0-9]", "");
assertEquals(EXPECTED, result);

如果执行测试,它将通过。正则表达式模式相当直观。对于不熟悉语法的人来说,注意以下几点可能会有帮助:

  • [^…] - 不是\[…\]中的任何一个字符。例如,[^0-9]匹配任何非数字。
  • \s - 匹配任何空白字符,如空格和制表符。

此外,Java的正则表达式引擎支持POSIX字符类别。因此,我们可以直接使用\\\\p{Punct}字符类别来匹配任何属于!"#$%&'()*+,-./:;<=>?@\[\\\]^\_\{|}~:`中的字符

String result = INPUT.replaceAll("\\p{Punct}", "");
assertEquals(EXPECTED, result);

当我们运行上述测试时,它也会通过。

4. 当输入为Unicode字符串时

我们已经成功地看到了两种移除输入字符串中标点的方法。如果我们仔细观察INPUT字符串,我们会发现它由ASCII字符组成。

可能会有人问:如果我们收到这样的字符串:

static final String UNICODE_INPUT = "3 March März 三月 březen маршировать (!@#$%^&*{}[];':\")<>,.";

除了数字3、空格字符和标点符号,这个输入还包括英语、德语、中文、捷克语和俄语中的单词“March”。因此,与之前的INPUT变量不同,UNICODE_INPUT变量包含Unicode字符。

移除标点后,预期的结果应该如下所示:

static final String UNICODE_EXPECTED = "3 March März 三月 březen маршировать ";

接下来,让我们测试这两种方法是否仍然适用于这种输入:

String result1 = UNICODE_INPUT.replaceAll("[^\\sa-zA-Z0-9]", "");
assertNotEquals(UNICODE_EXPECTED, result1);

上述测试通过了。但值得注意的是,断言是assertNotEquals()。所以,“移除[^\\sa-zA-Z0-9]”方法并未产生预期的结果。让我们看看它实际产生的结果:

String actualResult1 = "3 March Mrz  bezen  ";
assertEquals(actualResult1, result1);

所以,所有非ASCII字符连同标点一起被移除了。显然,“移除[^\\sa-zA-Z0-9]”方法对Unicode字符串不起作用

但是,我们可以通过将“a-zA-Z”范围替换为“\p{L}”来修复它

String result3 = UNICODE_INPUT.replaceAll("[^\\s\\p{L}0-9]", "");
assertEquals(UNICODE_EXPECTED, result3);

值得一提的是,\\p{L}匹配任何字母,包括Unicode字符。

另一方面,“移除\\p{Punct}”方法仍然适用于Unicode输入

String result2 = UNICODE_INPUT.replaceAll("\\p{Punct}", "");
assertEquals(UNICODE_EXPECTED, result2);

这是因为\\\\p{Punct}只匹配标点字符。

5. 总结

在这篇文章中,我们学习了如何使用标准的String.replaceAll()方法从字符串中移除标点符号:

  • String.replaceAll("[^\\\\sa-zA-Z0-9]", "") - 只适用于包含ASCII字符的输入字符串
  • String.replaceAll("\\\\p{Punct}", "") - 适用于ASCII和Unicode字符串
  • String.replaceAll("[^\\\\s\\\\p{L}0-9]", "") - 适用于ASCII和Unicode字符串

如往常一样,这里展示的所有代码片段都可以在GitHub上找到。