java 使用流操作字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31977356/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using streams to manipulate a String
提问by KidCrippler
Let's say that I want to remove all the non-letters from my String
.
假设我想从我的String
.
String s = "abc-de3-2fg";
I can use an IntStream
in order to do that:
我可以使用 anIntStream
来做到这一点:
s.stream().filter(ch -> Character.isLetter(ch)). // But then what?
What can I do in order to convert this stream back to a String
instance?
我该怎么做才能将此流转换回String
实例?
On a different note, why can't I treat a String
as a stream of objects of type Character
?
另一方面,为什么我不能将 aString
视为类型为对象的流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);
According to the javadoc, the Stream
's creation signature is as follows:
根据javadoc,Stream
的创建签名如下:
Stream.of(T... values)
Stream.of(T... 值)
The only (lousy) way that I could think of is:
我能想到的唯一(糟糕)方法是:
String s = "abc-de3-2fg";
Stream<Character> stream = Stream.of(s.charAt(0), s.charAt(1), s.charAt(2), ...)
And of course, this isn't good enough... What am I missing?
当然,这还不够好……我错过了什么?
采纳答案by Stuart Marks
Here's an answer the second part of the question. If you have an IntStream
resulting from calling string.chars()
you can get a Stream<Character>
by casting to char
and then boxing the result by calling mapToObj
. For example, here's how to turn a String
into a Set<Character>
:
这是问题的第二部分的答案。如果你有一个IntStream
调用的结果,string.chars()
你可以Stream<Character>
通过转换到char
然后通过调用将结果装箱来获得 a mapToObj
。例如,以下是将 aString
转换为 a 的方法Set<Character>
:
Set<Character> set = string.chars()
.mapToObj(ch -> (char)ch)
.collect(Collectors.toSet());
Note that casting to char
is essential for the boxed result to be Character
instead of Integer
.
请注意,强制转换char
为对于装箱结果是Character
而不是Integer
.
Now the big problem with dealing with char
or Character
data is that supplementary characters are represented as surrogate pairsof char
values, so any algorithm with deals with individual char
values will probably fail when presented with supplementary characters.
现在,随着处理的大问题char
或Character
数据是增补字符表示为代理对的char
值,因此与个别交易的任何算法char
值可能会在与增补字符呈现失败。
(It may seem like supplementary characters are an obscure Unicode feature that we don't need to worry about, but as far as I know, all emoji are supplementary characters.)
(看起来补充字符是我们不需要担心的晦涩的 Unicode 功能,但据我所知,所有表情符号都是补充字符。)
Consider this example:
考虑这个例子:
string.chars()
.filter(Character::isAlphabetic)
...
This will failif presented with a string that contains the code point U+1D400 (Mathematical Bold Capital A). That code point is represented as a surrogate pair in the string, and neither value of a surrogate pair is an alphabetic character. To get the correct result, you'd need to do this instead:
如果出现包含代码点 U+1D400(数学粗体大写 A)的字符串,这将失败。该代码点表示为字符串中的代理对,并且代理对的值都不是字母字符。要获得正确的结果,您需要这样做:
string.codePoints()
.filter(Character::isAlphabetic)
...
I recommend always using codePoints()
.
我建议始终使用codePoints()
.
Now, given an IntStream
of code points, how can one reassemble it into a String? Sleiman Jneidi's answeris a reasonable one (+1), using the three-arg collect()
method of IntStream
.
现在,给定一个IntStream
代码点,如何将它重新组合成一个字符串?Sleiman Jneidi 的回答是合理的 (+1),使用 的三参数collect()
方法IntStream
。
Here's an alternative:
这是一个替代方案:
StringBuilder sb = ... ;
string.codePoints()
.filter(...)
.forEachOrdered(sb::appendCodePoint);
return sb.toString();
This might be a bit more flexible, in cases where you already have a StringBuilder
that you're using to accumulate string data. You don't have to create a new StringBuilder
each time, nor do you have to convert it to a String
afterwards.
这可能会更灵活一些,在您已经有一个StringBuilder
用于累积字符串数据的情况下。您不必StringBuilder
每次都创建一个新的,也不必String
事后将其转换为 a 。
回答by Sleiman Jneidi
The method chars
returns an IntStream
. You just missing the collector
该方法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);
回答by Tagir Valeev
Unfortunately such scenario is badly supported by Java 8 Stream API. My StreamExlibrary adds a couple of helper methods to work with such streams: IntStreamEx.charsToString()
, IntStreamEx.codePointsToString()
and IntStreamEx.toCharArray()
. Also I introduced the primitive collectors like IntCollector
which may help collecting the primitive streams in some non-trivial way.
不幸的是,Java 8 Stream API 严重支持这种情况。我的StreamEx库添加了一些辅助方法来处理这样的流:IntStreamEx.charsToString()
,IntStreamEx.codePointsToString()
和IntStreamEx.toCharArray()
. 我还介绍了原始收集器,例如IntCollector
它可能有助于以某种非平凡的方式收集原始流。
Here's how your task can be solved using the StreamEx library:
以下是使用 StreamEx 库解决您的任务的方法:
String result = IntStreamEx.ofChars(s).filter(Character::isLetter).charsToString();
Or with codepoints:
或者使用代码点:
String result = IntStreamEx.ofCodePoints(s)
.filter(Character::isLetter)
.codePointsToString();