使用流操作字符串

2022-09-01 20:53:35

假设我想从我的.String

String s = "abc-de3-2fg";

我可以使用 一个来做到这一点:IntStream

s.stream().filter(ch -> Character.isLetter(ch)).  // But then what?

为了将此流转换回实例,我该怎么办?String

另一方面,为什么我不能将 a 视为类型的对象流?StringCharacter

String s = "abc-de3-2fg";

// Yields a Stream of char[], therefore doesn't compile
Stream<Character> stream = Stream.of(s.toCharArray());

// Yields a stream with one member - s, which is a String object. Doesn't compile
Stream<Character> stream = Stream.of(s);

根据 javadoc,的创建签名如下所示:Stream

流.of(T... 值)

我能想到的唯一(糟糕的)方式是:

String s = "abc-de3-2fg";
Stream<Character> stream = Stream.of(s.charAt(0), s.charAt(1), s.charAt(2), ...)

当然,这还不够好...我错过了什么?


答案 1

这是问题第二部分的答案。如果你有一个调用的结果,你可以得到一个 通过强制转换为,然后通过调用 来装箱结果。例如,下面介绍如何将 a 转换为 :IntStreamstring.chars()Stream<Character>charmapToObjStringSet<Character>

Set<Character> set = string.chars()
    .mapToObj(ch -> (char)ch)
    .collect(Collectors.toSet());

请注意,强制转换为 对于将框化结果替换为 至关重要。charCharacterInteger

现在处理或数据的最大问题是增补字符表示为值的代理项对,因此任何具有处理单个值的算法在显示增补字符时都可能失败。charCharactercharchar

(看起来增补字符是一个晦涩难懂的Unicode功能,我们不需要担心,但据我所知,所有的表情符号都是增列字符。

请考虑以下示例:

string.chars()
      .filter(Character::isAlphabetic)
      ...

如果显示的字符串包含码位 U+1D400(数学粗体大写字母 A),则此操作将失败。该代码点在字符串中表示为代理项对,代理项对的值都不是字母字符。要获得正确的结果,您需要改为执行以下操作:

string.codePoints()
      .filter(Character::isAlphabetic)
      ...

我建议始终使用.codePoints()

现在,给定一个代码点,如何将其重新组合成字符串?Sleiman Jneidi的答案是合理的(+1),使用三 arg 方法。IntStreamcollect()IntStream

这是另一种选择:

StringBuilder sb = ... ;
string.codePoints()
      .filter(...)
      .forEachOrdered(sb::appendCodePoint);
return sb.toString();

这可能更灵活一些,如果您已经有一个用于累积字符串数据的情况。您不必每次都创建一个新的,也不必在之后将其转换为 a。StringBuilderStringBuilderString


答案 2

该方法返回一个 .你只是错过了收集器charsIntStream

String s = "abc-de3-2fg";
String s1 = s.chars().filter(Character::isLetter)
            .collect(StringBuilder::new,StringBuilder::appendCodePoint,StringBuilder::append)
            .toString();
System.out.println(s1);