Skip to content

fix(extract): セクション名マッチで 中黒 (・) と空白を正規化#9

Merged
beatinaniwa merged 1 commit into
mainfrom
fix/section-name-normalize-nakaguro
May 12, 2026
Merged

fix(extract): セクション名マッチで 中黒 (・) と空白を正規化#9
beatinaniwa merged 1 commit into
mainfrom
fix/section-name-normalize-nakaguro

Conversation

@beatinaniwa

@beatinaniwa beatinaniwa commented May 12, 2026

Copy link
Copy Markdown
Owner

Summary

EDINET 提出企業ごとに、 章見出しでの 中黒 (・) の有無や全角/半角の空白の差し込み方が揺れているため、 MatchSection が一部の企業の section を取り逃がしていたのを修正します。

実例

  • 日本マクドナルドホールディングス 第55期 (S100XS22): 「コーポレート・ガバナンスの状況等」 (中黒あり)
  • 株式会社セブン&アイ・ホールディングス 第20期 (S100VT7P): 「コーポレートガバナンスの状況等」 (中黒なし)

旧実装 (strings.Contains(heading, name)) は文字単位の一致なので、 KnownSections の Names が中黒入りで定義されている場合、 中黒なしの提出書類見出しに一致しません。 結果としてセブン&アイ governance は section 未検出 → cli は警告 + full doc を返す → 利用側 (ingest_edinet.py 等) で full doc を section テキストとして誤って保存、 という現象が起きていました。

Changes

internal/extract/sections.go

  • normalizeForMatch(s) ヘルパーを追加: 中黒 (・、 U+30FB) + 半角空白 + 全角空白 (U+3000) + tab + 改行 を削除した正規形を返す
  • MatchSection 内で heading と KnownSections の Name を 正規化済みで比較

internal/extract/html_test.go

  • TestMatchSection_NakaguroVariants を追加: 中黒あり/なし + 半角空白 + 全角空白の 6 パターンを担保

実 EDINET docID での検証

S100VT7P (セブン&アイ HD 第20期) governance:

  • before: section 未検出 → cli warning + full doc 282,362 chars (内容: 表紙ページ〜)
  • after: section=governance 59,998 chars (内容: 「①コーポレートガバナンスに関する基本的な考え方」 〜)

Test plan

補足

  • 同様の正規化は今後 KnownSections に追加される他の section にも自動適用されます
  • 将来的に NFKC 正規化を入れる選択肢もありますが、 まずは目視で揺れが確認されている 中黒 + 空白に絞った最小範囲の修正に留めました

EDINET 提出企業によって、 章見出しでの 「中黒 ・」 の有無や全角/半角の空白の差し込み方が揺れている。 例:

- 日本マクドナルドホールディングス 第55期 (S100XS22): 「コーポレート・ガバナンスの状況等」 (中黒あり)
- 株式会社セブン&アイ・ホールディングス 第20期 (S100VT7P): 「コーポレートガバナンスの状況等」 (中黒なし)

旧実装 (\`strings.Contains(heading, name)\` ベース) は文字一致なので、 KnownSections の Names が中黒入りで定義されている場合 (governance)、 中黒なしの 提出書類の見出しに一致しなかった。 結果として:

- セブン&アイ governance: cli は section 未検出として warning + full doc を返す
- ingest_edinet.py 側は full doc を section テキストとして保存、 BLEED_MARKER_PATTERN がほぼ任意の位置で truncate → 表紙ページから始まる 19,526 chars の無意味な内容で governance.json が生成されていた (見かけは bleed_truncated)

## 修正

\`MatchSection\` の比較を、 中黒 (・、 U+30FB) + 半角/全角空白 + tab + 改行 を除いた正規形で行うように変更。

## 検証

S100VT7P (セブン&アイ HD 第20期) governance:

- before: section 未検出 → warning + full doc 282,362 chars (内容: 表紙ページ〜)
- after: section=governance 59,998 chars (内容: 「①コーポレートガバナンスに関する基本的な考え方」〜)

既存テスト全件パス。 新規テスト \`TestMatchSection_NakaguroVariants\` で 中黒あり/なし + 半角/全角空白の 6 パターンを担保。

## 影響範囲

- 中黒揺れがある heading を含む EDINET 有報の section 抽出が改善
- 同様の正規化が今後追加される他の section にも自動的に適用される
@beatinaniwa beatinaniwa merged commit 38de09e into main May 12, 2026
2 checks passed
@beatinaniwa beatinaniwa deleted the fix/section-name-normalize-nakaguro branch May 12, 2026 03:37
beatinaniwa added a commit that referenced this pull request May 17, 2026
PR #8 で導入した depth-aware section flush は physical h-level (h1〜h6 タグ) のみを見ていたが、 EDINET 提出書類によっては 章見出しと sub-heading に同じ <h3> タグを使っているため、 sub-heading で section が誤 flush される。 具体例:

セコム 第64期 (S100W3TS) の risk 章:
- `<h3>3【事業等のリスク】` ← 章 marker
- `<h3>(1)事業環境に起因するリスク` ← sub-heading だが同じ <h3>
- `<h3>(2)経営戦略に関するリスク` ← 同上
- `<h3>4【経営者による財政状態...】` ← 次の章 marker (mda)

PR #8 の depth-only flush は (1)事業環境に起因するリスク で risk を flush してしまい、 risk セクションが 4,050 chars → 286 chars (intro のみ) に劇的に短縮されていた (= silent data loss)。

## 修正

### chapter vs sub-numbering を識別

`chapterHeadingPrefixRe` で 「N【...】」 「第N【...】」 形式の **章 marker** のみを検出。 「(1)」 「①」 「a.」 などの sub-numbering はマッチしない。

`walkForSections` の非マッチ heading の flush 判定を:

旧: `level > 0 && level <= state.depth` (depth のみ)
新: `level > 0 && level <= state.depth && isChapterHeading(headingText)` (depth + 章 marker)

これで、 sub-heading は同 depth でも章を flush せず sub-section として継続。 章 marker が出てきたら flush する。

### EDINET フッターアーティファクトを除去

各 `_honbun_*.htm` の末尾には `有価証券報告書(通常方式)_<14桁timestamp>` という EDINET メタ情報が書かれている。 walker はこれを最後の section の末尾に取り込んでしまうため、 governance / financial 等の末尾に metadata text が混入していた。

`filingFooterRe` で末尾の `有価証券報告書(通常方式)_<digits>` を section text から除去。 各 section の Text に `stripFilingFooter` を適用。

## 検証

| docID | section | before (PR #8+#9) | after (本 PR) |
|---|---|---|---|
| S100W3TS (セコム) | risk | **286 (regression)** | **4,050 (restored)** |
| S100XTNW (楽天) | governance | 8,813 | 38,947 (footer/章 marker 整理) |
| S100XS22 (マクドナルド) | governance | 30,201 | 30,170 (footer -31 chars) |
| S100VT7P (セブン&アイ) | governance | 59,998 | 59,967 (footer -31 chars) |

全 section の text 末尾 100 chars に `有価証券報告書(通常方式)_` を検出しなくなった。

## Tests

- `TestExtractSections_SubHeadingSameHTag`: セコムパターン (同 h3 タグで章 + sub) で section が正しく分割されること
- `TestIsChapterHeading`: 章 marker と sub-numbering の判定が正しいこと
- `TestStripFilingFooter`: footer 除去ロジック単体
- `TestExtractSections_FilingFooterStripped`: section 抽出時に footer が除去されること

`go test ./...` 全件パス。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant