textdoc

package
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package textdoc 把 OFD 页面中的文字对象提取为带位置的条目,供文本、Markdown 等编码器复用。它只依赖 OFD 模型与解析器,不感知任何输出格式。

Index

Constants

This section is empty.

Variables

View Source
var (
	// NumberedHeaderRegex 匹配「1.」「1.2.」「1.2.3.」等形式的多级编号标题。
	NumberedHeaderRegex = regexp.MustCompile(`^(\d+\.)(?:\d+\.)*`)

	// ParagraphMarkerRegex 匹配常见的中文段落起始标记。
	ParagraphMarkerRegex = regexp.MustCompile(
		`^(第\s*[0-9一二三四五六七八九十百千零两]+\s*[条编]|[((][一二三四五六七八九十百0-9]+[))]|[一二三四五六七八九十百]+、)`)

	// PageNumberRegex 匹配纯页码,例如「12」。
	PageNumberRegex = regexp.MustCompile(`^\d{1,3}$`)

	// DashPageNumberRegex 匹配带破折号的页码,例如「- 12 -」「— 12 —」。
	DashPageNumberRegex = regexp.MustCompile(`^[—–\-]\s*\d+\s*[—–\-]$`)
)

Functions

func BodyFontSize added in v0.1.4

func BodyFontSize(entries []Entry) float64

BodyFontSize 返回一页的正文基准字号:出现次数最多的字号,平票取较小值。 找不到有效字号时兜底 6mm。

func Count

func Count(documents []*parser.Document) int

Count 统计所有文档体的非空页面总数。

func DetectHeadingLevel added in v0.1.4

func DetectHeadingLevel(text string, fontSize, bodyFontSize float64) int

DetectHeadingLevel 判断一行文字的标题层级,不是标题时返回 0。

编号标题优先于字号:「1.2 引言」无论字号多大都是标题。字号派生的层级还要过 两道否决——首字符必须是大写字母、数字或汉字(避免把以标点开头的正文误判), 且不能是正文形态(过长或以句末标点结尾)。

func DisplayWidth

func DisplayWidth(text string) int

DisplayWidth 返回按终端显示列数计算的宽度:CJK 等全角字符占两列,其余字符 占一列,保证多栏文字的列位置对齐。

func EnsureUTF8

func EnsureUTF8(value string) string

EnsureUTF8 保证输出文本是合法 UTF-8。OFD 规范要求文字为 UTF-8,但部分第三方 文档会写入 GBK 等本地编码的原始字节;这里先尝试按 GBK 解码,失败时再把无法 识别的字节替换为 U+FFFD,避免 .txt/.md 出现非法 UTF-8 导致乱码。

func Finite

func Finite(value float64) bool

Finite 判断浮点数是否为有限值(非 NaN、非 Inf)。

func IsPageNumber added in v0.1.4

func IsPageNumber(text string) bool

IsPageNumber 判断文本是否为页码形式(纯数字或两侧带破折号的数字)。

func IsPageNumberRow added in v0.1.4

func IsPageNumberRow(row []Entry, pageHeight float64) bool

IsPageNumberRow 判断一行是否为页码行。只有页码形式的文本且位于页面顶部或 底部(页眉/页脚区域)时才认定为页码,避免把表格或数据中的纯数字行删掉。

func JoinText

func JoinText(row []Entry) string

JoinText 用空格连接一行中的所有文字。

func ParagraphStarts added in v0.1.4

func ParagraphStarts(rows [][]Entry, inTable []bool, rowInfos []RowInfo) []bool

ParagraphStarts 判断每个正文行是否为段落起点。段落边界按以下信号:

  1. 段首缩进:行左边缘比正文左边距多出约一个字符宽;
  2. 段落标记:第 X 条、第 X 编、(一)、一、 等;
  3. 纵向间距明显大于页内常见行距(部分文档使用段间距而非缩进)。

func RowLeft

func RowLeft(row []Entry) float64

RowLeft 返回一行的最小 X 坐标。

func RowRight

func RowRight(row []Entry) float64

RowRight 返回一行的最大右边界。

func RowSize

func RowSize(row []Entry) float64

RowSize 返回一行中的最大字号。

func RowTolerance

func RowTolerance(a, b, unit float64) float64

RowTolerance 返回聚行时允许的纵向容差。

func RowTop

func RowTop(row []Entry) float64

RowTop 返回一行的最小 Y 坐标。

func Rows

func Rows(entries []Entry) [][]Entry

Rows 按 Y 坐标把文字条目聚成行,行内按 X 排序。

Types

type Entry

type Entry struct {
	Text  string
	X     float64
	Y     float64
	Size  float64
	Width float64

	// FontName 是字体资源里的字体名,解析不到时为空串。OFD 只在文字对象上给
	// FontID,名字要查文档体的字体资源;结构化输出(DOCX 的 w:rFonts)需要它,
	// 纯文本与 Markdown 则不关心。
	FontName string
	// Bold 与 Italic 供逐 run 还原字符形态,Weight 达到 boldWeight 即视为粗体。
	Bold   bool
	Italic bool

	// Source 记录该条目来自页面的哪一部分。同样的文字放在不同位置,含义差别
	// 很大:页面图层是正文,模板层常放页眉页脚与页面装饰,批注层则是水印、
	// 印章、签章这类叠加在正文上的标记。是否采信由输出格式决定,因此这里
	// 只如实记录来源而不做过滤。
	Source EntrySource
}

Entry 是一个待输出的文字对象及其在页面中的位置与尺寸(毫米,原点在页面左上角)。

type EntrySource added in v0.1.4

type EntrySource int

EntrySource 是文字条目的来源。

const (
	// EntrySourcePage 是页面自身图层里的文字,即正文。
	EntrySourcePage EntrySource = iota
	// EntrySourceTemplate 是页面模板里的文字,常是页眉页脚与页面边框装饰。
	EntrySourceTemplate
	// EntrySourceAnnotation 是批注外观里的文字,即叠加在正文上的水印、印章与
	// 签章标记。实测保密宣传册的整页「保密资料」水印就属于这一类:81 个文字
	// 对象分布在批注里,而页面图层只有 5 个真实内容对象。
	EntrySourceAnnotation
)

func (EntrySource) String added in v0.1.4

func (s EntrySource) String() string

String 返回来源的短名称,供日志与测试断言使用。

type Image added in v0.1.4

type Image struct {
	// Data 是原始编码字节(PNG/JPEG 等),按原样内嵌,不重新编码。
	Data []byte
	// Extension 是不含点的扩展名,决定 MIME 与文件名。
	Extension string
	// X 与 Y 是图片左上角位置(毫米,原点在页面左上角)。
	X float64
	Y float64
	// Width 与 Height 是显示尺寸(毫米)。
	Width  float64
	Height float64
}

Image 是页面里的一张可内嵌图片。

func ExtractImages added in v0.1.4

func ExtractImages(doc *parser.Document, page *parser.Page, limit int) []Image

ExtractImages 提取一页里可内嵌的图片,按阅读顺序(Y 升序,Y 相同按 X 升序) 排列,与 Rows 对文字的排序约定一致。

type Page

type Page struct {
	Entries []Entry
	Width   float64
	Height  float64

	// Source 是提取来源,供需要非文字图元的输出格式(DOCX 内嵌图片)回到原页面
	// 继续提取。纯文本与 Markdown 输出不使用这两个字段。
	Source *parser.Page
	Owner  *parser.Document
}

Page 保存单页的文字条目以及该页物理尺寸,用于按列对齐和页眉页脚判定。

func Collect

func Collect(documents []*parser.Document, start, end int) []Page

Collect 提取全局页索引范围 [start, end) 内的页面。调用方需保证 start/end 合法(通常先经页码校验);end 超出总页数时按总页数截断。

func ExtractPage

func ExtractPage(doc *parser.Document, page *parser.Page) Page

ExtractPage 提取单个页面的文字条目和物理尺寸。

func (Page) WithoutSource added in v0.1.4

func (p Page) WithoutSource(drop EntrySource) Page

WithoutSource 返回剔除指定来源条目后的页面副本。批注里的水印与印章属于叠加 标记,不是正文,结构化输出通常要排除;模板层的页眉页脚则常是真内容, 是否剔除由调用方决定。

type RowInfo added in v0.1.4

type RowInfo struct {
	Text    string
	MaxSize float64
	// Level 是标题层级,1..6;0 表示不是标题。
	Level int
	// IsTitle 等价于 Level > 0。
	IsTitle bool
	// IsList 由 DOCX 的列表识别写入,其他输出格式不使用,保持 false。
	IsList bool
}

RowInfo 保存页内一行的文本与标题判定结果。

type Table

type Table struct {
	Start  int
	End    int
	Header []string
	Rows   [][]string
}

Table 描述一个已识别的表格。Start/End 是页内行索引(含),Header 为表头 单元格文本,Rows 为数据行。

func DetectTables

func DetectTables(rows [][]Entry) []Table

DetectTables 在已按行分组的文字条目中识别表格。算法:

  1. 行内按水平间距切分单元格,含两个及以上单元格的行为候选网格行;
  2. 用候选网格行的单元格区间求并,间隔(白槽)处切分得到列;
  3. 每个候选行的单元格必须各自落在唯一列内且覆盖至少两列,才认定为表格行;
  4. 只有一个单元格且落在唯一列内的行作为续行,合并到最近的表格行;
  5. 被非表格行(标题、页脚等)隔开的多行网格行组成一个表格。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL