Pattern to Stream

前から常に思っていたのですが、Java8 には、java.util.regex.Pattern に、splitAsStream があるのに、
matchAsStream に相当するマッチしたものをストリームで返すメソッドが提供されてないんだと不満でした。
Java9 なら、Matcher に、 Stream を取得できる
public Stream results()
が提供される予定のようです。もうすぐ 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());
}