Java 使用流操作字符串
假设我想从Java 使用流操作字符串,java,string,lambda,java-8,java-stream,Java,String,Lambda,Java 8,Java Stream,假设我想从字符串中删除所有非字母 String s = "abc-de3-2fg"; 我可以使用IntStream来实现这一点: s.stream().filter(ch -> Character.isLetter(ch)). // But then what? 要将此流转换回字符串实例,我可以做些什么 另一方面,为什么我不能将字符串视为字符类型的对象流 String s = "abc-de3-2fg"; // Yields a Stream of char[], therefor
字符串中删除所有非字母
String s = "abc-de3-2fg";
我可以使用IntStream
来实现这一点:
s.stream().filter(ch -> Character.isLetter(ch)). // But then what?
要将此流转换回字符串
实例,我可以做些什么
另一方面,为什么我不能将字符串
视为字符
类型的对象流
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);
当然,这还不够好。。。我缺少什么?方法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);
不幸的是,Java8流API严重支持这种场景。我的库添加了两个助手方法来处理这些流:,和。此外,我还介绍了一些原语收集器,例如,它们可以帮助以某种非平凡的方式收集原语流
以下是如何使用StreamEx库解决您的任务:
String result = IntStreamEx.ofChars(s).filter(Character::isLetter).charsToString();
或使用代码点:
String result = IntStreamEx.ofCodePoints(s)
.filter(Character::isLetter)
.codePointsToString();
下面是问题第二部分的答案。如果调用string.chars()
生成了IntStream
,则可以通过强制转换到char
,然后调用mapToObj
来装箱结果,从而获得流。例如,下面介绍如何将字符串
转换为集合
:
如果显示的字符串包含代码点U+1D400(数学粗体大写字母a),则该操作将失败。该代码点在字符串中表示为代理项对,代理项对的值都不是字母字符。要获得正确的结果,您需要执行以下操作:
string.codePoints()
.filter(Character::isAlphabetic)
...
我建议始终使用codePoints()
现在,给定一个IntStream
代码点,如何将其重新组合成字符串?是合理的(+1),使用IntStream
的三个参数collect()
方法
这里有一个替代方案:
StringBuilder sb = ... ;
string.codePoints()
.filter(...)
.forEachOrdered(sb::appendCodePoint);
return sb.toString();
如果您已经有了一个StringBuilder
用于积累字符串数据,那么这可能会更灵活一些。您不必每次都创建一个新的StringBuilder
,也不必在以后将其转换为String
。很抱歉,但这看起来非常冗长(我不熟悉java 1.8)。难道没有更简洁的东西吗?也许用一个reduce方法?使用Scala,您可以编写类似于“abc-de3-2fg”.filter(Isleter).mkString(“”)的代码,在Scala中,字符串上的过滤器是字符串,这里不是这种情况,chars()在这里返回IntStream,IntStream上的过滤器返回IntStream,有一个名为collector.joining()的简化方法但这需要将每个字符转换成字符串,我只是感到惊讶。我刚刚做了几次尝试来提供一个更简洁的解决方案,但没有成功(使用mapping、toArray和其他一些东西)。我是Java的支持者,但Scala如此受欢迎也就不足为奇了。@FrancisToth总是有int[]filtered=s.codePoints().filter(Character::isleter.toArray();s=新字符串(已过滤,0,已过滤.length)代码>。不需要收集器。@FrancisToth基本上,尝试将流转换为字符串
被视为边缘大小写。(在某些方面,这是合理的。)我试着玩了一点StreamEx,看起来很不错。我试试看:-)@kidclemper,很高兴听到这个消息。如果您有任何增强建议或发现错误,请随时联系。将此答案标记为IMO认可,这是最优雅的解决方案,不需要第三方库
string.chars()
.filter(Character::isAlphabetic)
...
string.codePoints()
.filter(Character::isAlphabetic)
...
StringBuilder sb = ... ;
string.codePoints()
.filter(...)
.forEachOrdered(sb::appendCodePoint);
return sb.toString();