LoginSignup
0
1

More than 5 years have passed since last update.

Natural 575 Detector Kotlin

Last updated at Posted at 2017-10-21

CircleCI

Natural 575 Detector Kotlin

n575を検出します

ずっとなぜ人間が自然言語の文脈から575を検出できるのか不思議でした。これをなんか自動化できないでしょうか

JVMで動く形態素解析エンジンであるKuromojiと、neologdをもちい、任意の標準入力のテキストを自動で575をスキャンします

requirement

$ kotlinc -version
info: kotlinc-jvm 1.1.51 (JRE 1.8.0_144-b01)
$ java -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

コンパイル

Gradleを使うほど大規模でないので、Makeでなんとかしています

$ make

実行

$ cat same-japanese-context.txt | make run

サンプルの実行

「小説家になろう」の「蜘蛛ですが、なにか?」さんのテキストを利用しました

$ cat resource/kumodesuga | make run
猛毒に/麻痺属性を/追加して
完全に/丸投げだけど/これくらい
恩恵を/最大限に/利用して
片方が/鑑定様や/探知さん
恐怖が/私のことを/ジワジワと
攻撃の/仕様からして/自分にも
魔王でも/我ら魔族は/魔王様
本人の/意思を無視して/静止して
多分だけ/どこの世界の/言葉なん
準備は/万端という/ことですね
牽制と/たまに本気の/攻撃を
...

コード

説明するほどは長くないんですが、こんな感じです

余力があれば、BoWに変換して機械学習で、川柳らしさを計算して、その確率値が高いものだけを残すということをもできるので、暇な人はやってみるといいでしょう

githubでコードの全体と依存する形態素解析ライブラリを公開しています

fun main(args : Array<String>) {
  val tokenizer = Tokenizer()

  val contain = mutableListOf<MutableList<Triple<String,String,String>>>()
  BufferedReader(InputStreamReader(System.`in`)).lines()
  .forEach { 
    val oneLine = mutableListOf<Triple<String,String,String>>()
    tokenizer.tokenize(it).map { 
      Pair(it.getSurface(), it.getAllFeatures()) 
    }.map {
      val (surface, features) = it 
      var kana = features.split(",").last()
      //listOf("ァ", "ィ", "ゥ", "ェ", "ォ").map { kana = kana.replace(it, "") }
      val noun = features.split(",").first()
      oneLine.add( Triple(surface, kana, noun) )
    }
    contain.add(oneLine)
  }

  // 575が成立しているところをスキャンする
  contain.map { oneLine ->
    // separater
    val job = thread {
      val maxDepth = 100000L
      var depth = 0L
      outer@for( i in (0..oneLine.size-1) ) {
        for( k in (i+1..oneLine.size-1) ) {
          for( l in (k+1..oneLine.size-1) ) {
            for( m in (l+1..oneLine.size-1) ) {
              depth ++
              if( depth > maxDepth) break@outer
              if( oneLine.slice(i..k).map { it.second.length }.sum() == 5 && 
                  oneLine[i].third == "名詞" && oneLine[k].third == "助詞" &&
                  oneLine.slice(k+1..l).map { it.second.length }.sum() == 7 &&  
                  oneLine[k+1].third == "名詞" && oneLine[l].third == "助詞" &&
                  oneLine.slice(l+1..m).map { it.second.length }.sum() == 5 && 
                  oneLine[l+1].third == "名詞"  && (oneLine[m].third == "助詞" || oneLine[m].third == "名詞" ) && oneLine.slice(l+1..m).size > 1 ) {

                // validation 
                val sentence1 = oneLine.slice(i..k).map { it.first }.joinToString("") 
                val sentence2 = oneLine.slice(k+1..l).map { it.first }.joinToString("")
                val sentence3 = oneLine.slice(l+1..m).map { it.first }.joinToString("")

                val concat = sentence1 + "/" + sentence2 + "/" + sentence3
                if( sentence1.length > 5 || sentence2.length > 7 || sentence3.length > 5) continue
                if( concat.contains(",") || concat.contains("、") || concat.contains("・") ) continue
                println(sentence1 + "/" + sentence2 + "/" + sentence3)
              }
            }
          }
        }
      }
    }
    job
  }.map {
    it.join()
  }

}

ライセンス

MIT

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1