こんばんは。
今日から数日は少し涼しいみたいですね。
30℃を超えると仮死状態になるので、ありがたいです。
最近ちょっと自然言語処理をしたかったのでKuromojiを使っているのですが、
JapaneseTokenizerがstream化できなくてなんかもやもやするんです。
やっぱりwhileってあんまり使わないんですかね?
private List<String> toWords(String src){ List<String> ret = new ArrayList<>(); try (JapaneseTokenizer jt = new JapaneseTokenizer(null, false, JapaneseTokenizer.Mode.NORMAL)) { CharTermAttribute ct = jt.getAttribute(CharTermAttribute.class); PartOfSpeechAttribute partOfSpeech = jt.getAttribute(PartOfSpeechAttribute.class); jt.setReader(new StringReader(src)); jt.reset(); while (jt.incrementToken()) { if ("名詞".equals(partOfSpeech.getPartOfSpeech().split("-")[0])) { ret.add(ct.toString()); } } } catch (IOException e) { e.printStackTrace(); } return ret; }
こんな感じのやつ。
ResultSetなんかもこのタイプですよね。
ためしに、前回のStreamHelperにこんなのを足してみますか?
(※Javadocに無責任なことを書いてはいけません)
/** * while風なStream * * <pre> * 第一引数が第二引数な間だけ、第三引数したStreamを返す。 * (何言ってるかわからない) * </pre> */ public static <T, S> Stream<S> whileStream(T target, Predicate<T> whileFunc, Function<T, S> convertFunc) { return StreamSupport.stream(new Spliterator<>(target, whileFunc, convertFunc), false); } private static class Spliterator<T, S> extends Spliterators.AbstractSpliterator<S> { private T target; private Predicate<T> whileFunc; private Function<T, S> convertFunc; private Spliterator(T target, Predicate<T> whileFunc, Function<T, S> convertFunc) { super(Long.MAX_VALUE, ORDERED); this.target = target; this.whileFunc = whileFunc; this.convertFunc = convertFunc; } @Override public boolean tryAdvance(Consumer<? super S> action) { if (this.whileFunc.test(target)) { action.accept(this.convertFunc.apply(target)); return true; } else { return false; } } }
で、こんな感じ。
private List<String> toWords(String src) { try (JapaneseTokenizer jt = new JapaneseTokenizer(null, false, JapaneseTokenizer.Mode.NORMAL)) { jt.setReader(new StringReader(src)); jt.reset(); return StreamHelper.whileStream(jt, StreamHelper.throwingPredicate(j -> j.incrementToken()), this::toToken) .filter(p -> "名詞".equals(p.getValue())) .map(p -> p.getKey()) .collect(Collectors.toList()); } catch (IOException e) { return Collections.EMPTY_LIST; } } private Pair<String, String> toToken(JapaneseTokenizer jt) { CharTermAttribute ct = jt.getAttribute(CharTermAttribute.class); PartOfSpeechAttribute partOfSpeech = jt.getAttribute(PartOfSpeechAttribute.class); return new Pair(ct.toString(), partOfSpeech.getPartOfSpeech().split("-")[0]); }
ちなみにPairはパッケージがjavafx.utilなので、FXじゃないアプリで使っていいのか怪しいです。
自分で作るか、Apache CommonsとかEclipse Collectionsのを使ったほうがいいかもしれませんね。
(あ、あとはAbstractMap.SimpleEntryとか…)