# What Types of Chapter Headings Can book-to-skill Detect?

> Discover the nine chapter heading types book-to-skill detects across multiple languages. Explore how layered regex patterns enable versatile content analysis.

- Repository: [Virgilio Junior/book-to-skill](https://github.com/virgiliojr94/book-to-skill)
- Tags: deep-dive
- Published: 2026-08-28

---

**book-to-skill detects nine distinct categories of chapter headings across English, Chinese, Thai, Hindi, Korean, Persian, and other languages using layered regex patterns implemented in [`book_to_skill/utils.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/utils.py).**

The `book-to-skill` open-source project extracts structured knowledge from technical books and documentation by identifying chapter boundaries. Understanding what types of chapter headings the tool can detect is essential for processing multilingual publications, as the library implements language-specific regex patterns that recognize everything from explicit English labels to CJK ideographic counters and Perso-Arabic ordinals.

## Detection Architecture and Core Logic

At the heart of the detection system lies the `detect_structure()` function in [`book_to_skill/utils.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/utils.py). This high-level orchestrator returns a dictionary containing the chapter count, detection method (`numeric`, `structural`, or `none`), sample headings, and a Table-of-Contents presence flag. The actual pattern matching is handled by `_match_chapter_number()`, which iterates through language-specific regexes, and `_chapter_number()`, which extracts the numeric value from matched headings.

## Supported Chapter Heading Formats

### Explicit English-Style and Western Headings

The tool recognizes explicit chapter labels using the `_EXPLICIT_CHAPTER` regex. This pattern matches words like `Chapter`, `Capítulo`, `Chapitre`, `Kapitel`, `Capitolo`, and `Hoofdstuk`, as well as the abbreviated form `ch.`. These markers must be followed by a number—either Arabic or Roman—and may include optional trailing punctuation or title text.

### Plain Numbered Headings

Common in technical O'Reilly-style books, plain numbered headings use a simple Arabic numeral followed by **at least two spaces** and then title text (e.g., `1  Introduction`). The `plain` regex inside `_match_chapter_number` specifically requires this spacing to avoid misclassifying list items like `1. Item` as chapters.

### Roman Numeral Headings

The `_ROMAN_HEAD` pattern identifies upper-case Roman numerals at the start of a line followed by punctuation (`I:`, `II.`). For Markdown documents, the `_LC_MD_ROMAN` regex detects lower-case Roman numerals within ATX headings (e.g., `## i. introduction`).

### Chinese Chapter Headings

The `_CN_CHAPTER` regex handles traditional Chinese patterns such as `第 N 章`, `第 N 回`, and `第 十二 节`, as well as variants like `第一讲`. For Markdown-formatted Chinese texts, `_MD_CN_HEADING` recognizes CJK headings prefixed with hash symbols (e.g., `# 第 1 章 …` or `# 一 · 缘起`).

### Thai Chapter Headings

Thai chapter markers are detected via `_TH_CHAPTER`, which matches words like `บทที่`, `ตอนที่`, and `ภาคที่` (including short forms). These may be followed by Thai digits (⁰‑⁹) or Arabic digits, and the pattern optionally accounts for Markdown heading prefixes (`##`).

### Hindi (Devanagari) Chapter Headings

The `_HI_CHAPTER` pattern identifies the word `अध्याय` followed by either Devanagari digits or Arabic numerals. This detection works on raw text lines or when prefixed by Markdown heading markers.

### Korean Chapter Headings

Korean documents use the classifier `제` plus a numeral and specific suffixes. The `_KO_CHAPTER` regex matches patterns like `제12장` (chapter), `제3편` (volume), `제2절` (section), or `제5관` (part). It also handles inserted-chapter suffixes (`의 N`) and Markdown prefixes.

### Persian (Farsi) Chapter Headings

Persian detection uses multiple patterns including `_FA_DIGITS` and `_FA_ONES` to match labels like `فصل` (chapter) or `بخش` (section) with Arabic/Persian digits, Unicode-Indic digits, or word ordinals (e.g., `فصل اول`, `فصل بیست و یکم`). The `_fa_chapter_number` helper function processes these variations, with a secondary pass handling Markdown heading markers.

### Markdown and AsciiDoc Structural Headings

When no numeric chapters are detected, the system falls back to structural analysis using `_ATX_HEADING` (for `# Title` and `## Section`) and `_SETEXT_UNDERLINE` (for `===` and `---` underlines). These patterns are defined in [`book_to_skill/utils.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/utils.py) and are invoked by `_structural_chapter_count` only when the numeric scan returns no results.

## The Detection Pipeline

The chapter detection flow follows a strict four-step sequence to maximize accuracy across languages:

1. **Normalization**: Kangxi-radical numerals are translated to standard CJK ideographs using `_KANGXI_NUMERAL_TRANS` before pattern matching begins.

2. **Fast Numeric Scan**: `_match_chapter_number` tests plain, explicit, Roman, CJK, Thai, Hindi, Korean, and Persian patterns in order against each line.

3. **Secondary Markdown Pass**: If a line is preceded by a Markdown or AsciiDoc prefix, `_MD_HEADING_PREFIX` strips the prefix and re-tests the line against all numeric patterns.

4. **Structural Fallback**: When no numeric headings are discovered, `_structural_chapter_count` analyzes generic document structure using ATX and Setext patterns.

## Practical Implementation Examples

The `_chapter_number` helper function demonstrates how the regexes extract values from diverse heading formats. Below is a runnable example showing detection across all supported languages:

```python
from book_to_skill.utils import _chapter_number

samples = [
    "Chapter 5: Introduction",               # English explicit

    "I. The Loomings",                        # Roman numeral

    "第 3 章 数据结构",                       # Chinese

    "## บทที่ ๒ การทำงานของระบบ",           # Thai (Markdown prefix)

    "अध्याय 7 प्रोग्रामिंग",                  # Hindi

    "제12장 계약",                             # Korean

    "فصل ۲۲ تحلیل داده‌ها",                    # Persian (Arabic digits)

    "1  Overview of Algorithms",              # Plain numbered (>=2 spaces)

]

for s in samples:
    print(f"{s!r:40} → {_chapter_number(s)}")

```

Output:

```text
'Chapter 5: Introduction'                → 5
'I. The Loomings'                        → 1
'第 3 章 数据结构'                       → 3
'## บทที่ ๒ การทำงานของระบบ'           → 2

'अध्याय 7 प्रोग्रामिंग'                  → 7
'제12장 계약'                             → 12
'فصل ۲۲ تحلیل داده‌ها'                    → 22
'1  Overview of Algorithms'              → 1

```

## Summary

- **book-to-skill** detects chapter headings across nine major categories including English explicit labels, plain numbered sections, Roman numerals, Chinese, Thai, Hindi, Korean, and Persian formats.
- The core detection engine resides in [`book_to_skill/utils.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/utils.py), specifically within `detect_structure()`, `_match_chapter_number()`, and language-specific regex constants like `_EXPLICIT_CHAPTER`, `_CN_CHAPTER`, and `_KO_CHAPTER`.
- Detection requires specific formatting rules, such as **at least two spaces** after plain numbers, to distinguish chapters from list items.
- The pipeline uses a four-step process: Kangxi radical normalization, fast numeric scanning, Markdown prefix stripping, and structural fallback.
- Extensive test coverage in [`tests/test_book_to_skill.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/tests/test_book_to_skill.py) and [`tests/test_numbered_headings.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/tests/test_numbered_headings.py) validates each heading style.

## Frequently Asked Questions

### Can book-to-skill detect chapters in languages not listed in the documentation?

According to the source code in [`book_to_skill/utils.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/utils.py), the tool is limited to the specific regex patterns implemented for English, Chinese, Thai, Hindi, Korean, Persian, and Roman numerals. If a language uses a different chapter marker not covered by these patterns, the tool will fall back to structural heading detection or return no chapters. You would need to extend the `_match_chapter_number()` function with additional regex patterns for unsupported languages.

### How does book-to-skill avoid confusing list items with chapter headings?

The `plain` regex inside `_match_chapter_number()` specifically requires **at least two spaces** between a leading Arabic numeral and the following text. This pattern distinguishes true chapter headings like `1  Introduction` from numbered list items like `1. Item` or `1) Item`, which typically use single punctuation without extensive whitespace.

### What happens if a document uses both numeric chapters and Markdown headings?

The detection pipeline prioritizes numeric patterns. `detect_structure()` first calls `_match_chapter_number()` to identify explicit, Roman, CJK, Thai, Hindi, Korean, or Persian chapter markers. Only when no numeric chapters are found does the system invoke `_structural_chapter_count()` to count generic Markdown ATX or Setext headings. This ensures that a chapter titled `## Chapter 3` is recognized as chapter 3 via the explicit English pattern rather than being treated as a generic structural heading.

### Where are the regex patterns for chapter detection defined?

All chapter-heading regexes are defined as module-level constants in [`book_to_skill/utils.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/utils.py). Key patterns include `_EXPLICIT_CHAPTER` for Western labels, `_CN_CHAPTER` and `_MD_CN_HEADING` for Chinese, `_TH_CHAPTER` for Thai, `_HI_CHAPTER` for Hindi, `_KO_CHAPTER` for Korean, and `_FA_DIGITS` with `_fa_chapter_number()` for Persian. The structural fallback patterns `_ATX_HEADING` and `_SETEXT_UNDERLINE` are also located in this file.