我们想要删除String
中的所有非字母。
String s = "abc-de3-2fg";
我可以使用IntStream
来执行此操作:
s.stream().filter(ch -> Character.isLetter(ch)). // But then what?
如何将此流转换回String
实例?
另外,为什么我不能将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);
根据javadoc,Stream
的创建签名如下:
Stream.of(T ...值)
我能想到的唯一(糟糕的)方式是:
String s = "abc-de3-2fg";
Stream<Character> stream = Stream.of(s.charAt(0), s.charAt(1), s.charAt(2), ...)
当然,这还不够好......我错过了什么?
答案 0 :(得分:10)
这是问题第二部分的答案。如果您通过调用IntStream
得到string.chars()
,则可以通过转换为Stream<Character>
获得char
,然后通过调用mapToObj
来结果。例如,以下是如何将String
转换为Set<Character>
:
Set<Character> set = string.chars()
.mapToObj(ch -> (char)ch)
.collect(Collectors.toSet());
请注意,投放到char
对于包装结果至关重要Character
而不是Integer
。
现在处理char
或Character
数据的一个大问题是,补充字符表示为char
值的代理对,所以任何算法都是处理个别char
值时,如果出现补充字符,可能会失败。
(看起来补充字符是一个不起眼的Unicode功能,我们不需要担心,但据我所知,所有表情符号都是补充字符。)
考虑这个例子:
string.chars()
.filter(Character::isAlphabetic)
...
如果显示包含代码点U + 1D400(数学大胆资本A)的字符串,则失败。该代码点表示为字符串中的代理项对,并且代理项对的值都不是字母字符。要获得正确的结果,您需要改为:
string.codePoints()
.filter(Character::isAlphabetic)
...
我建议始终使用codePoints()
。
现在,给定IntStream
个代码点,如何将其重组为String? Sleiman Jneidi's answer是合理的(+1),使用collect()
的三参数IntStream
方法。
这是另一种选择:
StringBuilder sb = ... ;
string.codePoints()
.filter(...)
.forEachOrdered(sb::appendCodePoint);
return sb.toString();
如果您已经使用StringBuilder
来累积字符串数据,那么这可能会更灵活一些。您不必每次都创建新的StringBuilder
,也不必在之后将其转换为String
。
答案 1 :(得分: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);
答案 2 :(得分:4)
不幸的是,Java 8 Stream API严重支持这种情况。我的StreamEx库添加了一些辅助方法来处理这些流:IntStreamEx.charsToString()
,IntStreamEx.codePointsToString()
和IntStreamEx.toCharArray()
。我还介绍了像IntCollector
这样的原始收集器,它可以帮助以某种非平凡的方式收集原始流。
以下是使用StreamEx库解决您的任务的方法:
String result = IntStreamEx.ofChars(s).filter(Character::isLetter).charsToString();
或使用代码点:
String result = IntStreamEx.ofCodePoints(s)
.filter(Character::isLetter)
.codePointsToString();
答案 3 :(得分:0)
public String removeNonLetters(String value) {
return value.chars()
.mapToObj(i -> (char) i) // map int to char
.filter(Character::isLetter) // filter non-letters
.map(String::valueOf) // required for joining
.collect(Collectors.joining());
}