知財のあれこれをPythonで何とかする

### クレームツリーを何とかする（その2）
前回の投稿（[クレームツリーを何とかする（その1）](https://qiita.com/nop_z80/items/7fc4405ff4b35747912d)）で紹介したプログラムでは請求項が記載されたファイル（meisai.txt）における請求項の記載が「請求項ｎまたはｍ」や「請求項ｎないしｍ」といった記載ではうまく動作しないので、meisai.txtを書き換えるプログラムを作成してみました。
クレームツリーを何とかする（その1）のプログラムを実行する直前に以下のprogram1を実行ください。

```python:Program1.py
import re
import shutil
import unicodedata

#part1 前処理
shutil.copy("meisai.txt","meisai_bk.txt")

meisai = []
ms_base = []
f = open('meisai.txt', 'r')#ANSIで保存すること
ms_base = f.read()
f.close()
ms_base=unicodedata.normalize("NFKC", ms_base)#請求項数の数値を半角にする
meisai = re.split("【",ms_base)#請求項ごとに分割する

meisai.pop(0)
meisai2=[]

#part2 「または」処理
pattern = r"請求項(\d+)または(\d+)"
replacement = r"請求項\1または請求項\2"

for ms_part in meisai:
    new_text = re.sub(pattern, replacement, ms_part)
    new_text = new_text.rstrip("\n")#文末改行を削除
    meisai2.append(new_text)

#part3 「ないし」処理
meisai3=[]
pattern = r"請求項(\d+)ないし(\d+)"

for ms_part in meisai2:
    match = re.search(pattern, ms_part)
    if match:
        start = int(match.group(1))
        end = int(match.group(2))
        replacement = "または".join([f"請求項{i}" for i in range(start, end + 1)])
        new_text = re.sub(pattern, replacement, ms_part)
        new_text = new_text.rstrip("\n")#文末改行を削除
        meisai3.append(new_text)
    else:
        meisai3.append(ms_part)

#part4 meisai.txt書き戻し
with open('meisai.txt', 'w', encoding='shift_jis') as f:
    print("",file=f)
for elm in meisai3:
    print("【"+elm.lstrip()) #elmの先頭のスペースを削除して【を付ける
    with open('meisai.txt', 'a', encoding='shift_jis') as f:
        print("【"+elm.lstrip(), file=f)

```
以下のサンプルをファイル名「meisai.txt」としてANSI形式で保存します。
<details><summary>サンプルデータ</summary>

```
【請求項１】制御ユニット。
【請求項２】請求項１に記載の制御ユニット。
【請求項３】請求項１または２に記載の制御ユニットを有する情報処理装置。
【請求項４】請求項１または２に記載の制御ユニットを有する情報処理装置。
【請求項５】請求項３または４に記載の情報処理装置。
【請求項６】請求項３ないし５のいずれかに記載の情報処理装置。
【請求項７】請求項３または４に記載の情報処理装置。
【請求項８】請求項４ないし７のいずれかに記載の情報処理装置。
【請求項９】請求項４ないし８のいずれかに記載の情報処理装置。
【請求項１０】請求項３ないし９のいずれかに記載の情報処理装置。
【請求項１１】請求項１０に記載の情報処理装置。
【請求項１２】請求項１０または１１に記載の情報処理装置。
【請求項１３】請求項３ないし１２のいずれかに記載の情報処理装置。
```
</details>
program1を実行すると以下のように「請求項ｎまたはｍ」は「請求項ｎまたは請求項ｍ」に、「請求項ｎないしｍ」は「請求項ｎまたは請求項ｎ+1・・・・または請求項ｍ」に変換し、meisai.txtを書き換えて上書き保存します。

<details><summary>サンプルデータ(変換後)</summary>

```
【請求項1】制御ユニット。
【請求項2】請求項1に記載の制御ユニット。
【請求項3】請求項1または請求項2に記載の制御ユニットを有する情報処理装置。
【請求項4】請求項1または請求項2に記載の制御ユニットを有する情報処理装置。
【請求項5】請求項3または請求項4に記載の情報処理装置。
【請求項6】請求項3または請求項4または請求項5のいずれかに記載の情報処理装置。
【請求項7】請求項3または請求項4に記載の情報処理装置。
【請求項8】請求項4または請求項5または請求項6または請求項7のいずれかに記載の情報処理装置。
【請求項9】請求項4または請求項5または請求項6または請求項7または請求項8のいずれかに記載の情報処理装置。
【請求項10】請求項3または請求項4または請求項5または請求項6または請求項7または請求項8または請求項9のいずれかに記載の情報処理装置。
【請求項11】請求項10に記載の情報処理装置。
【請求項12】請求項10または請求項11に記載の情報処理装置。
【請求項13】請求項3または請求項4または請求項5または請求項6または請求項7または請求項8または請求項9または請求項10または請求項11または請求項12のいずれかに記載の情報処理装置。
```
</details>

### プログラムのポイント
- (part1)
meisai.txtをリストmeisaiに取り込んで数値を全角→半角に変換しています。
また今回meisai.txt自体を書き換えてしまうことから、以下の構文で処理前にファイル名meisai_bk.txtのバックアップファイルを作るようにしました
```python:
shutil.copy("meisai.txt","meisai_bk.txt")
```

- (part2)
「請求項ｎまたはｍ」を「請求項ｎまたは請求項ｍ」に変換します。
正規表現で「請求項ｎまたはｍ」の記載部分を抽出してre.sub構文で置き換え処理をしています。
```python:part2
pattern = r"請求項(\d+)または(\d+)"
replacement = r"請求項\1または請求項\2"
new_text = re.sub(pattern, replacement, ms_part)
```
- (part3)
「請求項ｎないしｍ」を「請求項ｎまたは請求項ｍ」に変換します。
正規表現で「請求項ｎないしｍ」の記載部分を抽出してre.sub構文で置き換え処理をしています。
```python:part3
pattern = r"請求項(\d+)ないし(\d+)"
match = re.search(pattern, ms_part)
if match:
    start = int(match.group(1))
    end = int(match.group(2))
    replacement = "または".join([f"請求項{i}" for i in range(start, end + 1)])
    new_text = re.sub(pattern, replacement, ms_part)
```
以下のリスト内包表記でｎとｍの間の数値の生成をして文字列「請求項」とつなげて「請求項3または請求項4または請求項5または・・」を作成しています。
```python:
replacement = "または".join([f"請求項{i}" for i in range(start, end + 1)])
```
### 注意点１
明細書によっては「請求項ｎ、ｍ」や「請求項ｎ乃至ｍ」といった表記をしている場合がありますので、その場合プログラムのpart2、part3を以下のように書き換える必要があります。

```python:請求項ｎ、ｍ
#part2の20行を書き換える
pattern = r"請求項(\d+)、(\d+)"
```
```python:請求項ｎ乃至ｍ
#part3の29行を書き換える
pattern = r"請求項(\d+)乃至(\d+)"
```
### 注意点２
プログラムが【請求項】の「【」を手掛かりに処理(リストの分割)をしているので、想定しない場所に「【」が存在すると動作がおかしくなる可能性があります。
```python:
meisai = re.split("【",ms_base)#請求項ごとに分割する
```
【】は必ず【請求項】の書式として使用されるようお願いします。

### 最後に
注意点１に挙げたように明細書は様々な表現のパターンがありますので、パターンに応じたプログラムの書き換えが必要な場合もありますが、pythonは保守性が高いので、こういった書き換えを要するようなプログラムに対しても適しているのではと思います。
今回の記事がお役に立てれば幸いです。