さあ、河川の数を数えろ

国土数値情報(河川データ、平成18年度〜20年度、40都県)に存在する河川の数を数えてみました。
五歳男児の流行語をタイトルに借りて*1、簡単な Ruby プログラムを組んで処理してみました。

プログラム

# -*- coding: utf-8 -*-
# count_rivers.rb
require 'rubygems'
require 'zip/zip'
require 'nokogiri'

class Parser < Nokogiri::XML::SAX::Document
  def initialize
    @mode = nil
    @buf = ''
    @code = nil
    @name = nil
  end

  def start_element(name, attrs)
    @mode = name if %w{ksj:RIC ksj:RIN}.include?(name)
  end

  def characters(text)
    @buf += text if @mode
  end

  def end_element(name)
    case name
    when 'ksj:GB02'
      print [@code, @name].join(' '), "\n"
      (@code, @name) = [nil, nil]
    when 'ksj:RIC'
      @code = @buf
    when 'ksj:RIN'
      @name = @buf
    end
    @buf = ''
    @mode = nil
  end

  def run
    Dir.glob('../../../src/ksj/river/*.zip') {|path|
      Zip::ZipFile.open(path) {|z|
        Nokogiri::XML::SAX::Parser.new(self).parse(
          z.get_input_stream(z.get_entry(
            File.basename(path).sub('zip', 'xml'))))
      }
    }
  end
end

Parser.new.run

処理結果

港湾や空港と比べて数が多いことと、同じ河川が別のレコードに分かれていることも多いので、次のようにして数えました。

$ ruby count_rivers.rb > rivers.txt
$ sort rivers.txt | uniq > rivers_su.txt
$ wc -l rivers_su.txt
   39529 rivers_su.txt

さらに、河川コードが振られていない川*2を除外すると何本になるか、次のようにして数えました。

$ grep --invert-match "000 " rivers_su.txt | wc -l
   20392

結論

国土数値情報によると、北海道、滋賀県京都府大阪府兵庫県奈良県和歌山県を除く日本の河川は39,529本程度(そのうち、河川コードがつくほどに大きな河川は 20,392本程度)ということになりました。

*1:港湾、空港、河川の中では河川が一番音の数が合います。本当は「日本の河川を数えろ」のほうが「河川の数を数えろ」よりも助詞「の」用法が合います。

*2:沢が多いようです。○○沢というような名前がつく小さな支流には個別の河川コードは振られておらず、かわりに末尾が ...000 である共有のコードが入っていました。