使用流来操作String

Kid*_*ler 18 java string lambda java-8 java-stream

假设我要删除我的所有非字母String.

String s = "abc-de3-2fg";
Run Code Online (Sandbox Code Playgroud)

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

s.stream().filter(ch -> Character.isLetter(ch)).  // But then what?
Run Code Online (Sandbox Code Playgroud)

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

另外,为什么我不能将a String视为类型的对象流Character

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);
Run Code Online (Sandbox Code Playgroud)

根据javadoc,其Stream创建签名如下:

Stream.of(T ...值)

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

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

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

Stu*_*rks 11

这是问题第二部分的答案.如果你有一个IntStream调用结果,string.chars()你可以Stream<Character>通过强制转换char,然后通过调用拳击结果mapToObj.例如,以下是如何将a String转换为Set<Character>:

Set<Character> set = string.chars()
    .mapToObj(ch -> (char)ch)
    .collect(Collectors.toSet());
Run Code Online (Sandbox Code Playgroud)

需要注意的是铸造char是必不可少的盒装结果为Character,而不是Integer.

现在,随着处理的大问题charCharacter数据是增补字符表示为代理对char值,因此与个别交易的任何算法char时增补字符呈现值可能会失败.

(看起来补充字符是一个不起眼的Unicode功能,我们不需要担心,但据我所知,所有表情符号都是补充字符.)

考虑这个例子:

string.chars()
      .filter(Character::isAlphabetic)
      ...
Run Code Online (Sandbox Code Playgroud)

如果显示包含代码点U + 1D400(数学大胆资本A)的字符串,则会失败.该代码点表示为字符串中的代理项对,并且代理项对的值都不是字母字符.要获得正确的结果,您需要这样做:

string.codePoints()
      .filter(Character::isAlphabetic)
      ...
Run Code Online (Sandbox Code Playgroud)

我建议一直使用codePoints().

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

这是另一种选择:

StringBuilder sb = ... ;
string.codePoints()
      .filter(...)
      .forEachOrdered(sb::appendCodePoint);
return sb.toString();
Run Code Online (Sandbox Code Playgroud)

如果您已经StringBuilder使用了累积字符串数据的情况,这可能会更灵活一些.您不必StringBuilder每次都创建新的,也不必在String之后将其转换为新的.


Sle*_*idi 7

该方法chars返回一个IntStream.你错过了收藏家

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

  • @FrancisToth总有`int [] filtered = s.codePoints().filter(Character :: isLetter).toArray(); s = new String(filtered,0,filtered.length);`.不需要收藏家. (3认同)
  • 我只是感到惊讶.我刚刚尝试了一些提供更简洁的解决方案,但没有任何成功(使用映射,toArray和其他一些东西).我是Java支持者,但难怪Scala如此受欢迎. (2认同)
  • @FrancisToth基本上,尝试将流转换为`String`被视为边缘情况.(理所当然,在某些方面.) (2认同)