RedPen を Java ライブラリとして使う

  • 12
    Like
  • 0
    Comment
More than 1 year has passed since last update.

概要

RedPen は JJUG CCC 2016 Spring 「Javaでつくる技術ドキュメントのバリデーション環境」で紹介されていた文書校正用ツールで、CLIやWebサーバ上で動作します。今すぐ試してみたい場合は公式サイトに デモ用 Web ツール が用意されていますので、そちらを試してみるとよいでしょう。

また、RedPen は Java のライブラリとしても提供されており、自分のアプリケーションでこのライブラリが提供するドキュメントチェック・校正の機能を簡単に利用することが可能です。というわけで、今回はこの RedPen を Java ライブラリとして使ってみました。

要件

ソースコード に Lambda 式や Stream API が利用されているため、 Java8 が必要です。

Software Version
Java 1.8.40 or greater
Maven 3.0.0 or greater

依存の追加

build.gradle の dependencies に下記を追記します。Gradle 以外は こちら をご参照ください。

dependencies
compile 'cc.redpen:redpen-core:1.5.5'

RedPen では文章を形態素に分割するのに kuromoji を使用しているようです。

dependencies_tree
\--- cc.redpen:redpen-core:1.5.5
     +--- com.atilika.kuromoji:kuromoji-ipadic:0.9.0
     |    \--- com.atilika.kuromoji:kuromoji-core:0.9.0
     +--- org.json:json:20080701
     +--- org.slf4j:slf4j-api:1.7.6
     +--- org.pegdown:pegdown:1.4.2
     |    \--- org.parboiled:parboiled-java:1.1.6
     |         +--- org.parboiled:parboiled-core:1.1.6
     |         +--- org.ow2.asm:asm:4.1
     |         +--- org.ow2.asm:asm-tree:4.1
     |         |    \--- org.ow2.asm:asm:4.1
     |         +--- org.ow2.asm:asm-analysis:4.1
     |         |    \--- org.ow2.asm:asm-tree:4.1 (*)
     |         \--- org.ow2.asm:asm-util:4.1
     |              \--- org.ow2.asm:asm-tree:4.1 (*)
     \--- org.apache.commons:commons-lang3:3.4

軽く試す

ソースコード全体

軽く試す用のコード
import java.util.ArrayList;
import java.util.List;

import cc.redpen.RedPen;
import cc.redpen.RedPenException;
import cc.redpen.config.Configuration;
import cc.redpen.config.ValidatorConfiguration;
import cc.redpen.model.Document;
import cc.redpen.model.Sentence;
import cc.redpen.validator.ValidationError;

public class RedPenVerification {
    public static void main(final String[] args) {
        final List<Document> documents = new ArrayList<>();
        documents.add(Document.builder()
                .setFileName("tested file")
                .addSection(0)
                .addParagraph()
                .addSentence(new Sentence("it is a piece of a cake.", 1))
                .addSentence(new Sentence("that is also a piece of a cake.", 2))
                .build());

        final RedPen redPen = getRedPenWithSentenceValidator();
        final List<ValidationError> errors = redPen.validate(documents).get(documents.get(0));
        errors.forEach(error -> {
            System.out.println(error.getLineNumber() + " " + error.getMessage());
        });
    }

    private static RedPen getRedPenWithSentenceValidator() {

        final Configuration configuration = Configuration.builder()
                .addValidatorConfig(
                        new ValidatorConfiguration("SentenceLength")
                            .addProperty("max_len", "5"))
                .build();
        try {
            return new RedPen(configuration);
        } catch (final RedPenException e) {
            e.printStackTrace();
        }
        return null;
    }
}

処理の概要

  1. main メソッドで documents という Document クラスの List オブジェクトを定義
  2. RedPen オブジェクトを生成して返す getRedPenWithSentenceValidator() メソッドをコール
  3. バリデーションを実施し、結果を List で受け取る
  4. errors の全要素に対し、行番号とエラーメッセージを表示

実行結果

実行結果
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
1 文長("24")が最大値 "5" を超えています。
2 文長("31")が最大値 "5" を超えています。

Validator

RedPen には多数の Validator が用意されています。どんな Validator が使えるかは公式ドキュメントの Validator に載っています。

RedPen オブジェクトを生成する際に configuration を渡せます。その configuration に、何をチェックさせるかの Validator を設定するようです。

Configuration
final Configuration configuration = Configuration.builder()
                .addValidatorConfig(
                        new ValidatorConfiguration("SentenceLength")
                            .addProperty("max_len", "5"))
                .build();
final RedPen redPen = new RedPen(configuration);

ValidatorConfiguration の初期化は下記の通り、コンストラクタで大項目を、addProperty で小項目を設定します。

ValidatorConfiguration
new ValidatorConfiguration("SentenceLength")
              .addProperty("max_len", "5")

SentenceLength

1 Sentence の長さが指定値以上なら警告します。

ValidatorConfiguration
new ValidatorConfiguration("SentenceLength")
              .addProperty("max_len", "5")
警告例
1 文長("24")が最大値 "5" を超えています。

InvalidExpression

不適切な表現を検出します。指定はファイルと文字列のいずれかで可能です。両方同時に指定してもよいです。

Property Description
dict ファイル、1行に1要素
list 文字列、「,」で区切る
ValidatorConfiguration(list)
new ValidatorConfiguration("InvalidExpression")
              .addProperty("list", "cake,a piece"))
ValidatorConfiguration(dict)
new ValidatorConfiguration("InvalidExpression")
                            .addProperty("dict", "invalid.txt")
invalid.txt
it is
that
警告例
1 不正な表現 "cake" がみつかりました。
1 不正な表現 "a piece" がみつかりました。
2 不正な表現 "cake" がみつかりました。
2 不正な表現 "a piece" がみつかりました。
1 不正な表現 "it is" がみつかりました。
2 不正な表現 "that" がみつかりました。

備考

「,」を含む表現を検出したい場合は dict を使う必要があります。

InvalidWord

不適切な単語を検出します。指定はファイルと文字列のいずれかで可能です。両方同時に指定してもよいです。 InvalidExpression との違いは スペースを含められない ことです。仮にスペースを含めたものを渡しても、コンパイルは通るが無視されます。

Property Description
dict ファイル、1行に1要素
list 文字列、「,」で区切る
ValidatorConfiguration(list)
new ValidatorConfiguration("InvalidWord")
              .addProperty("list", "cake,a piece"))
ValidatorConfiguration(dict)
new ValidatorConfiguration("InvalidWord")
              .addProperty("dict", "invalid.txt"))
invalid.txt
it is
that
警告例
1 不正な単語 "cake" がみつかりました。
2 不正な単語 "cake" がみつかりました。
2 不正な単語 "that" がみつかりました。

CommaNumber

1 sentence 内の「,」が指定数以上なら警告を出します。

ValidatorConfiguration
new ValidatorConfiguration("CommaNumber")
              .addProperty("max_num", "1")
警告例
2 カンマの数 (2) が最大の "1" を超えています。

WordNumber

1 sentence 内の単語が指定数以上なら警告を出します。

ValidatorConfiguration
new ValidatorConfiguration("WordNumber")
              .addProperty("max_num", "5")
警告例
1 一文に存在する単語数 (8) が最大値 "5" を超えています.。
2 一文に存在する単語数 (9) が最大値 "5" を超えています.。

備考

日本語ほか一部の言語では対応していません。

SuggestExpression

不適切な表現を検出し、代替表現を提示します。不適切表現と代替表現のペアはファイルに tsv 形式で保存し、指定します。

ValidatorConfiguration(dict)
new ValidatorConfiguration("SuggestExpression")
              .addProperty("dict", "suggest.txt")
suggest.tsv
noriben Nori-Bento

左が不適切表現、右が代替表現です。

警告例
1 不正な単語 "noriben" がみつかりました.かわりに "Nori-Bento" を利用してください。

InvalidSymbol

デフォルトだとマルチバイトの記号を検出します。

ValidatorConfiguration(dict)
new ValidatorConfiguration("InvalidSymbol")
警告例
2 不正なシンボル "?" がみつかりました。
3 不正なシンボル "。" がみつかりました。

SymbolWithSpace

「(」や「{」の前にスペースを置いていない場合は警告します。

ValidatorConfiguration(dict)
new ValidatorConfiguration("SymbolWithSpace")
警告例
1 シンボルの前にスペースが必要です (()。
2 シンボルの前にスペースが必要です ({)。

KatakanaEndHyphen

カタカナ語が長音記号で終わっている場合に警告します。技術系文書で3字以上のカタカナ語は長音記号を除くという慣習が由来です。

ValidatorConfiguration(dict)
new ValidatorConfiguration("KatakanaEndHyphen")

例えばこんな文章だと

.addSentence(new Sentence("彼は今日コンピューターを買った。", 3))
.addSentence(new Sentence("彼はキーとスキーとメジャーが好きだ。", 4))
.addSentence(new Sentence("彼はいつもラー油について熱弁をふるっています。", 5))

下記のように検出されます。

警告例
3 カタカナ単語 "コンピューター" に不正なハイフンが見つかりました。
4 カタカナ単語 "メジャー" に不正なハイフンが見つかりました。

備考

日本語特有の慣習であるため、日本語でしか使えません。

KatakanaSpellCheck

カタカナ語の表記揺れを検出します。辞書は効いているのかよくわかりません。

ValidatorConfiguration(dict)
new ValidatorConfiguration("KatakanaSpellCheck")
              .addProperty("dict", "spelling.txt")
              .addProperty("min_ratio", 0.8)
              .addProperty("min_freq", 1)

min_ratio で最低類似度(0.0-1.0)、min_freq(1-) で最低出現回数を設定します。マイナスや極端に大きい値も設定可能ですが、別に何もエラーは出ませんし、検出もされなくなるので意味はないでしょう。

例えばこんな文章だと

文章例
.addSentence(new Sentence("彼は今日ジェネリクスを知った。", 3))
.addSentence(new Sentence("彼はジェネリックスが好きだ。", 4))
.addSentence(new Sentence("彼はいつもジェネリクッスについて熱弁をふるっています。", 5))

下記の通り警告されます。

警告例
4 カタカナ単語 "ジェネリックス" に類似する単語 "ジェネリクス" が行 "3" でみつかりました。
5 カタカナ単語 "ジェネリクッス" に類似する単語 "ジェネリクス" が行 "3" でみつかりました。

備考

日本語でしか使えません。

SectionLength

Section 内の文字数が指定値を超えている場合は警告します。

ValidatorConfiguration
new ValidatorConfiguration("SectionLength")
              .addProperty("max_num", "40")

次のような Document が定義されている場合、

文章例
Document.builder()
                .setFileName("tested file")
                .addSection(0)
                .addParagraph()
                .addSentence(new Sentence("it is a noriben.", 1))
                .addSentence(new Sentence("is that also a piece of a cake?", 2))
                .addSentence(new Sentence("彼は今日ジェネリクスを知った。", 3))
                .addSentence(new Sentence("彼はジェネリックスが好きだ。", 4))
                .addSentence(new Sentence("彼はいつもジェネリクッスについて熱弁をふるっています。", 5))

下記のように警告されます。

警告例
0 セクション内の文字数が最大の"103"を超えています

残念ながらわかりにくいメッセージです。この103という数字は実際の文字数で、制限値が表示されていません。

ParagraphNumber

1セクション内のパラグラフ数が指定値を超えている場合は警告します。

ValidatorConfiguration(dict)
new ValidatorConfiguration("ParagraphNumber")
              .addProperty("max_num", "0")
警告例
0 セクション内のパラグラフ数が最大の"1"を超えています

SpaceBetweenAlphabeticalWord

アルファベット表記語の前後に半角スペースがない場合、警告します。

ValidatorConfiguration(dict)
new ValidatorConfiguration("SpaceBetweenAlphabeticalWord")
文章例
.addSentence(new Sentence("彼は今日ジェネリクスを知った。", 3))
.addSentence(new Sentence("彼はgenericsが好きだ。", 4))
.addSentence(new Sentence("彼はいつも inverted indexについて熱弁をふるっています。", 5))
警告例
2 アルファベット単語の後にスペースが存在しません。
4 アルファベット単語の前にスペースが存在しません。
4 アルファベット単語の後にスペースが存在しません。
5 アルファベット単語の前にスペースが存在しません。
5 アルファベット単語の後にスペースが存在しません。

Spelling

綴りが誤っている可能性を指摘します。

ValidatorConfiguration(dict)
new ValidatorConfiguration("Spelling")
              .addProperty("dict", "spelling.txt")
              .addProperty("list", "cake")
spelling.txt
noriben
文章例
.addSentence(new Sentence("it is a noribene.", 1))
.addSentence(new Sentence("is that also a piece of a cako?", 2))
警告例
1 ミススペルの可能性がある単語 "noribene" がみつかりました。
2 ミススペルの可能性がある単語 "cako" がみつかりました。

備考

英語でしか使えません。日本語の文章は全体が誤りだと判定されます。

DoubledWord

1つの文で同じ言葉が複数回登場したら警告します。

ValidatorConfiguration
new ValidatorConfiguration("DoubledWord")
                        .addProperty("dict", "white_list.txt")
                        .addProperty("list", "item")

dict と list で検査から除外する言葉を設定できます。

white_list.txt
のり弁
.addSentence(new Sentence("this good item is very good and item.", 3))
.addSentence(new Sentence("彼の今日のお昼はのり弁のり弁アンドのり弁だ", 4))
.addSentence(new Sentence("「のり弁のり弁」と、やけにのり弁を推すじゃないか。", 5))
警告例
3 一文に二回以上利用されている単語 "good" がみつかりました。

DoubledJoshi

同じ助詞が複数回続いた場合は警告します。

ValidatorConfiguration(dict)
new ValidatorConfiguration("DoubledJoshi")
              .addProperty("dict", "white_list.txt")
              .addProperty("list", "の")
文章例
.addSentence(new Sentence("彼の今日のお昼の弁当はのり弁とのり弁とのり弁だ", 1))
.addSentence(new Sentence("「のり弁のり弁」と、やけにのり弁を推すじゃないか。", 2))
警告例
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.ArrayList.rangeCheck(ArrayList.java:653)
    at java.util.ArrayList.get(ArrayList.java:429)
    at java.util.Collections$UnmodifiableList.get(Collections.java:1309)
    at cc.redpen.validator.sentence.DoubledJoshiValidator.validate(DoubledJoshiValidator.java:43)
    at cc.redpen.RedPen.lambda$null$33(RedPen.java:221)
    at java.util.ArrayList.forEach(ArrayList.java:1249)
    at cc.redpen.RedPen.lambda$runSentenceValidators$34(RedPen.java:221)
    at java.util.ArrayList.forEach(ArrayList.java:1249)
    at cc.redpen.RedPen.runSentenceValidators(RedPen.java:221)
    at cc.redpen.RedPen.validate(RedPen.java:135)

えっと、これはバグだと思いますが、いったいなぜ……

SuccessiveWord

同じ言葉が続いたら警告します。

ValidatorConfiguration
new ValidatorConfiguration("SuccessiveWord")
文章例
.addSentence(new Sentence("the item is is very good.", 1))
警告例
1 単語 "is" は連続して使用されています。

備考

英語や一部の言語(除日本語)でしか使えません。

JapaneseStyle

常体(だ、である調)と敬体(ですます調)が混在していたら警告を発するはずですが、動きませんでした。

ValidatorConfiguration
new ValidatorConfiguration("JapaneseStyle")
文章例
.addSentence(new Sentence("彼の今日のお昼の弁当はのり弁とのり弁とのり弁です。", 1))
.addSentence(new Sentence("それは贅沢である。", 2))
.addSentence(new Sentence("しかし彼には選択肢がなかったのである。", 3))

DoubleNegative

二重否定を検出します。が、動きませんでした。

ValidatorConfiguration
new ValidatorConfiguration("DoubleNegative")

FrequentSentenceStart

同じ書き出しになっている文章が連続した場合に警告します。

ValidatorConfiguration
new ValidatorConfiguration("FrequentSentenceStart")
              .addProperty("leading_word_limit", "3")
              .addProperty("percentage_threshold", "10")
              .addProperty("min_sentence_count", "1")```
文章例
.addSentence(new Sentence("This is a pen.", 1))
.addSentence(new Sentence("This is not a pipe.", 2))
.addSentence(new Sentence("This is a stcik.", 3))
警告例
3 75% of sentences start with "This is".
3 50% of sentences start with "This is a".
3 75% of sentences start with "This".
3 25% of sentences start with "This is not".

UnexpandedAcronym

アクロニム(=頭字語、名詞句の頭文字だけで構成した語)が拡張されていない時に指摘します。

ValidatorConfiguration
new ValidatorConfiguration("UnexpandedAcronym")
              .addProperty("min_acronym_length", "4")

"min_acronym_length" で許可するアクロニム長を指定できます。

文章例
.addSentence(new Sentence("We talk URL, HTTPS, DDoS, AOSSL", 1))
.addSentence(new Sentence("This is not a corba.", 2))
警告例
2 The expanded form of the acronym HTTPS is not present in the document.
2 The expanded form of the acronym AOSSL is not present in the document.

どうも小文字は検出できないようです。

備考

英語文でのみ使用できます。

WordFrequency

単語頻度を計測します。

ValidatorConfiguration
new ValidatorConfiguration("WordFrequency")
              .addProperty("deviation_factor", "4")
              .addProperty("min_word_count", "4")
文章例
.addSentence(new Sentence("We talk URL, HTTPS, DDoS, AOSSL", 1))
.addSentence(new Sentence("This is not a corba.", 2))
.addSentence(new Sentence("To be, or not to be, that is a question.", 3))
.addSentence(new Sentence("Let it be, let it be.", 4))
警告例
4 The word "a" comprises 8.70% of all words. Expected around 1.94%.
4 The word "be" comprises 17.39% of all words. Expected around 0.72%.
4 The word "or" comprises 4.35% of all words. Expected around 0.54%.
4 The word "question" comprises 4.35% of all words. Expected around 0.05%.
4 The word "this" comprises 4.35% of all words. Expected around 0.55%.
4 The word "is" comprises 8.70% of all words. Expected around 1.00%.
4 The word "it" comprises 8.70% of all words. Expected around 0.99%.
4 The word "we" comprises 4.35% of all words. Expected around 0.33%.
4 The word "not" comprises 8.70% of all words. Expected around 0.64%.
4 The word "talk" comprises 4.35% of all words. Expected around 0.01%.
4 The word "let" comprises 8.70% of all words. Expected around 0.05%.

備考

英語の文章でのみ使用できます。

NumberFormat

数値に「,」での区切りがない場合は指摘します。

ValidatorConfiguration
new ValidatorConfiguration("NumberFormat")
              .addProperty("decimal_delimiter_is_comma", "true")
              .addProperty("ignore_years", "false")
文章例
.addSentence(new Sentence("We was born 1969.", 1))
.addSentence(new Sentence("I spend \10000000.", 2))
警告例
1 Number 1969 requires a delimiter every three digits (eg: 1,000.00 or 1.000,00).
2 Number 00000 requires a delimiter every three digits (eg: 1,000.00 or 1.000,00).

備考

英語ないしフランス語の文章でのみ使用できます。

HankakuKana

半角カナを検出します。

ValidatorConfiguration
new ValidatorConfiguration("HankakuKana")
文章例
.addSentence(new Sentence("ガクガクプルプル", 1))
警告例
1 半角カナの文字 "カ" が見つかりました。
1 半角カナの文字 "゙" が見つかりました。
1 半角カナの文字 "ク" が見つかりました。
1 半角カナの文字 "カ" が見つかりました。
1 半角カナの文字 "゙" が見つかりました。
1 半角カナの文字 "ク" が見つかりました。
1 半角カナの文字 "フ" が見つかりました。
1 半角カナの文字 "゚" が見つかりました。
1 半角カナの文字 "ル" が見つかりました。
1 半角カナの文字 "フ" が見つかりました。
1 半角カナの文字 "゚" が見つかりました。
1 半角カナの文字 "ル" が見つかりました。

なお、半角スペースを含む文章だと半角スペースを全部検出します。使いどころが限定されかねないです。

備考

日本語でしか使えません。

Okurigana

不正な送り仮名を検出します。

ValidatorConfiguration
new ValidatorConfiguration("Okurigana")
文章例
.addSentence(new Sentence("声を荒らげるのは新らしいルールに従て必らずやめましょう。", 1))
警告例
1 不正な送り仮名 "荒ら" がみつかりました。
1 不正な送り仮名 "必ら" がみつかりました。

うーん……

備考

日本語でしか使えません。


まとめ

RedPen は Java のライブラリとして使うことができます。テキストを扱うツールやアプリケーションに組み込むことで、文章校正機能を提供することが可能となります。


リンク

  1. 公式サイト
  2. 公式サイトのデモ
  3. GitHub repository
  4. Javaでつくる技術ドキュメントのバリデーション環境……JJUG CCC 2016 Spring での発表資料です。