前から常に思っていたのですが、Java8 には、java.util.regex.Pattern に、splitAsStream があるのに、
matchAsStream に相当するマッチしたものをストリームで返すメソッドが提供されてないんだと不満でした。
Java9 なら、Matcher に、 Stream
public Stream
が提供される予定のようです。もうすぐ Java9 が出るだろうが実運用がすぐに移行させてはもらえないでしょうし。
そこで代替えを探していたらネットにはたくさん溢れていたので、その中で納得のいくもの1つに手を
加えたものと1、もう1つを紹介
パターンマッチ → Spliterator → StreamSupport → Stream という目的の為のイテレータ
import java.util.Spliterators.AbstractSpliterator; import java.util.function.Consumer; import java.util.regex.Matcher; /** * MatcherItrator */ public final class MatcherItrator extends AbstractSpliterator<CharSequence>{ private final Matcher matcher; public MatcherItrator(Matcher m){ super(m.regionEnd() - m.regionStart(), ORDERED|NONNULL); matcher = m; } @Override public boolean tryAdvance(Consumer<? super CharSequence> c){ if (!matcher.find()) return false; c.accept(matcher.group()); return true; } }
この super の呼び出し、super(Long.MAX_VALUE, ORDERED|NONNULL); でも良いのではないかと考えるが。。。
サンプル
String string = " abc_def_ghi_.."; StreamSupport.stream(new MatcherItrator(Pattern.compile("[a-z]+").matcher(string)), false) .forEach(e->{ System.out.println(e); });
Pattern と 検査対象を渡して、マッチ結果文字列Stream あるいは、MatchResultのStream を求める
ユーティリティクラス
import java.util.Spliterator; import java.util.Spliterators.AbstractSpliterator; import java.util.function.Consumer; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; import java.util.stream.StreamSupport; /** * MatcherStream */ public final class MatcherStream{ private MatcherStream(){} public static Stream<String> find(Pattern pattern, CharSequence input){ return findMatches(pattern, input).map(MatchResult::group); } public static Stream<MatchResult> findMatches(Pattern pattern, CharSequence input){ Matcher matcher = pattern.matcher(input); Spliterator<MatchResult> spliterator = new AbstractSpliterator<MatchResult>(Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.NONNULL){ @Override public boolean tryAdvance(Consumer<? super MatchResult> action){ if (!matcher.find()) return false; action.accept(matcher.toMatchResult()); return true; } }; return StreamSupport.stream(spliterator, false); } }
Stream
MatcherStream.find(Pattern.compile("[a-z]+"), string) .forEach(e->{ System.out.println(e); });
java.util.regex.MatchResult の Stream
MatcherStream.findMatches(Pattern.compile("[a-z]+"), string) .forEach(r->{ System.out.println(r.group()+" "+r.start()); }