NasupiiのPerl書抜帳

特許文献用の符号表作成支援プログラムソースコード


ソースコード

#####################################################################################################
# extract_marks.pl ver2.0
#
# このプログラムは UTF-8 で記述すること。他の文字コードで記述すると文字化けする。
#
# 特許公報から、符号を抽出し、csvファイルとして書き出す
# Copyright (C) Nasupii
#
# 2011/01/08 初版作成 (Shift-JIS専用)
# 2014/09/21 一部修正した (Ver 1.1)
#            符号に中点を追加した。第+数字を符号から除外した。
#            出力ファイル名を 符号表.csv に変えた
#            番号の最後のほうが抽出されないバグを修正した
# 2024/01/08 UTF-8に対応した。入力ファイルは Shift-JIS と UTF-8 を自動判定し、
#            出力ファイルは、Shift-JIS の csv ファイルとした。 (Ver.2.0)

#####################################################################################################

# 動作確認環境
#   Strawberry Perl 5.36.1.1 がインストールされた Windows 10 にて動作確認した。
#   Perl ver.5.10 以降なら、Encode が標準ライブラリーに加えられているので、たぶん動作するでしょう。
#   Windows の他のバージョンでもたぶん動作するでしょう。

# 使用方法
#   J-PlatPat等から入手した公報のテキストデータを、 "infile.txt" としてファイルする。
#   このプログラムを "infile.txt" があるフォルダにコピーし、ダブルクリックする。
#   符号及び符号の前後の文字列が抽出され、"符号表.csv" として カレントフォルダに書き出される。
#   MS-Excel等の表計算ソフトで "符号表.csv" を読み込むと、符号の一覧表が得られる。

# 注意事項
#   このソフトは構文解析を行っているわけではないので、符号ではないものまで抽出されたり、
#   同じ符号が複数回抽出されたりしているので、符号の前後の文字列を見ながら手作業での修正が必要です。
#   しかし、公報の全文からすべて手作業で符号を抽出するよりは、大幅な時間短縮が出来ます。
#   符号の判別法は、数字、アルファベット大文字小文字、’”,・だけからなる文字列を符合としています
#   上記以外の文字列が符号として使用されている場合は、抽出できない場合があります。

#####################################################################################################

use strict;
use warnings;
use utf8;
use Encode qw/decode encode/;
use Encode::Guess; 

binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';

my $fname_in = "infile.txt";
my $fname_out = encode("cp932", "符号表.csv");   # 漢字のファイル名を Shift-JIS(cp932) コードに変換

my ($nn, $an, $mk, $buf, $i, $j, $line, @lines, $enc);
my ($pre, $post, $mark, $mark1, $mark2, @marks, @marksx);

$nn  =       "0|1|2|3|4|5|6|7|8|9";
$an  = $nn . "|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z";
$an .=       "|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z";
$mk  = $an . "|’|”|,|・";  #Ver1.1 中点を追加

#####################################################################################################
# step0 読み込み、コード判定、コード変換
#####################################################################################################

$buf = "";

if(! open(IN, "<", $fname_in)) {                 # 入力ファイルを開く
  print "$fname_in が開けなかったので実行が中断されました。\n";
  exit;
}

while($line = <IN>) {                            # 入力ファイルを読み込む
  $buf .= $line;
}
close(IN);                                       # 入力ファイルを閉じる

$enc = guess_encoding($buf, qw/cp932 utf8/);     # 文字コードを判定する

if(! ref($enc) ){                                # エラートラップ
  print "文字コードが判定できなかったので実行が中断されました。\n";
  exit;
}

#print "文字コードを ", $enc->name, " と判定しました。\n";

$buf = decode($enc->name, $buf);                   # 読み込んだファイルをperlの内部表現に変換する


#####################################################################################################
# step1 半角文字を削除
#####################################################################################################

$buf =~ s/[ a-zA-Z0-9\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]//gm;

#####################################################################################################
# step2 "【"から始まる行を空行に変える
#####################################################################################################

$buf =~ s/^【.+?$//gm;

#####################################################################################################
# step3 句読点の後ろに改行を入れる
#####################################################################################################

$buf =~ s/、/、\n/gm;
$buf =~ s/。/。\n/gm;


#####################################################################################################
# step4 符号から除外する数字を削除し、改行に置き換える
# "請求項"+数字   "図"+数字   "文献"+数字    数字+"の実施形態"   数字+"の実施例"   数字+"の発明"
#####################################################################################################

$buf =~ s/(請求項|図|文献)($nn)+/\n/gm;
$buf =~ s/($nn)+(の実施形態|実施形態|の実施例|実施例|の発明|発明)/\n/gm;

#####################################################################################################
# step5 一行ずつの配列に分ける。
#####################################################################################################

@lines = split(/\n/, $buf);

#####################################################################################################
# step6 符号を含まない行を空行に変える
#####################################################################################################

foreach $line (@lines) {
  if($line !~ m/($mk)/) {
     $line = "";
  }
}

#####################################################################################################
# step7 空行を削除
#####################################################################################################

@lines = grep(/./, @lines);

#####################################################################################################
# step8 符号部の前に"="、後にタブを挿入
#####################################################################################################

foreach $line (@lines) {
  $line =~ s/((?:$mk)+)/=$1\t/g;
}

#####################################################################################################
# step9 行頭から始まる符号を削除
#####################################################################################################

foreach $line (@lines) {
  $line =~ s/^=($mk)+\t//g;
}

#####################################################################################################
# step10 第+数字を符号から除外する Ver1.1
#####################################################################################################

foreach $line (@lines) {
  $line =~ s/第=((?:$nn)+)\t/第$1/g;
}

#####################################################################################################
# step11 符号の前後を取り出し配列に入れる
#####################################################################################################

@marks = ();                                     # @marks を初期化
foreach $line (@lines) {
  $line = "\t" . $line . "=";
  while($line =~ s/\t(.*?)=(.*?)\t(.+?)=/\t$3=/) {
    push(@marks, join("\t", $2, $1, $3));
  }
}

#####################################################################################################
# step12 数字の桁数をそろえる(3桁と仮定する)
#####################################################################################################

foreach $line (@marks) {
  ($mark, $pre, $post) = split(/\t/, $line);
  if($mark =~ m/^($nn){3}/) {
    
  }elsif($mark =~ m/^($nn){2}/) {
    $mark = " " . $mark;
    $line = join("\t", $mark, $pre, $post);
  }elsif($mark =~ m/^($nn)/) {
    $mark = "  " . $mark;
    $line = join("\t", $mark, $pre, $post);
  }
}

#####################################################################################################
# step13 符号の前の文字を逆順に並べる
#####################################################################################################

foreach $line (@marks) {
  ($mark, $pre, $post) = split(/\t/, $line);
  $pre = reverse($pre);
  $line = join("\t", $mark, $pre, $post);
}

#####################################################################################################
# step14 並べ替え
#####################################################################################################

@marks = sort(@marks);

#####################################################################################################
# step15 符号及び符号の前が同一のものを一つにまとめる
#        同じ符号で符号の前に同じ文字列がある場合は、一番短いものにまとめる
#####################################################################################################

$i = 0;
$j = 1;
@marksx = ();
do {
  ($mark, $pre, $post) = split(/\t/, $marks[$i]);
  $mark1 = join("\t", $mark,$pre);
  ($mark, $pre, $post) = split(/\t/, $marks[$j]);
  $mark2 = join("\t", $mark,$pre);
  if($mark1 eq $mark2) {
    $j++;
  }elsif((length($mark1) < length($mark2)) and ($mark1 eq substr($mark2,0,length($mark1)))) {
    $j++; 
  }else{
    push(@marksx, $marks[$i]);
    $i = $j;
    $j++;
  }
}while ($j<=$#marks); 

push(@marksx, $marks[$i]); 

#####################################################################################################
# step16 符号の前の文字列を逆順から元に戻す
#####################################################################################################

foreach $line (@marksx) {
  ($mark, $pre, $post) = split(/\t/, $line);
  $pre = reverse($pre);
  $line = join("\t", $mark, $pre, $post);
}

#####################################################################################################
# step17 ファイル書き出し
#####################################################################################################

if(! open(OUT, ">:encoding(cp932)", $fname_out)) {         # ファイルを開く
  print "$fname_out が開けなかったので実行が中断されました。\n";
  exit; 
}
print OUT qq("","符号表"\n\n); 
foreach $line (@marksx) {
  ($mark, $pre, $post) = split(/\t/, $line);
  print OUT qq("$pre","[$mark]","$post"\n);
}
close(OUT);                                                # ファイルを閉じる
exit;

Copyright (C) Nasupii