Help us shape the future of Go! Take the 2026 Go Developer Survey

textdoc

package
v0.1.5 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 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