ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ANSI/ESD TR21.0-01-2018:引用边界与PDF文本提取

ANSI/ESD TR21.0-01-2018:引用边界与PDF文本提取 简介这份资源是ANSI ESD TR21.0-01-2018技术报告的电子版面向平板显示器Flat Panel Display制造环节中从事静电防护与EOS/ESD控制的工艺工程师、品质管理人员及设备集成技术人员。报告由ESD Association第21.0工作组编写针对平板显示制造过程中静电放电带来的良率损失与器件损伤问题给出控制思路与工程实践建议属于行业参考性技术文档适合有一定静电防护基础的读者查阅对照。资源共1个文件为PDF格式压缩包约985KB单文件结构便于在电脑或移动端直接打开检索也方便按章节摘取要点用于内部培训或工艺评审。文档为最新原版且文字可复制便于引用条款、做笔记和整理成中文对照资料。目前已有114人学习下载可作为FPD产线ESD防控方案设计、异常分析与标准培训时的参考依据。1. ANSI/ESD TR21.0-01-2018 到底是什么文件为什么可复制文字是个技术问题做静电防护的工程师多半遇到过这种尴尬客户审核时指着你们 ESD 管理计划里的一句话要求注明出自哪份文件的哪一版哪一条。你打开手头那份 ANSI/ESD TR21.0-01-2018选中一段准备复制粘贴粘出来却是一串方框和菱形问号。文件是真的字也在屏幕上就是提不出来。搜ESD这个词本身还会分叉。做静电控制的找的是 ESD Association 的技术出版物装系统的找的是另一类同名文件两边结果经常混在一起。ANSI/ESD TR21.0-01-2018 属于前者——前缀 ANSI 说明这份技术报告走完了相应批准流程ESD 是发布机构TR 表示它是技术报告而不是引用性标准21.0 是报告号01 是版次2018 是版本年份。这篇写给两类人需要在内部 ESD 管理文件里准确引用这份报告的人以及要把扫描版或受限 PDF 变成可搜索、可复制文本的人。前半程讲编号含义和引用边界后半程是命令、参数和排错。2. 拆开 ANSI/ESD TR21.0-01-2018 的六段编号TR 与 S/STM 的边界和版本怎么读2.1 六段编号各自代表什么ANSI 是批准环节。ESD Association 自己发布的技术报告走完相应的评审流程后文件名前面才挂得上 ANSI。它提供的是一层行业共识背书不等于强制约束力。ESD 是发布机构缩写指 ESD Association业内做静电放电控制标准的老牌组织常写作 EOS/ESD Association。看到这个缩写要立刻反应过来讲的是静电跟别的同名缩写没有关系。TR 是 Technical Report全文最需要盯住的两个字母。ESD Association 的出版物至少分这几类S 是标准STM 是标准测试方法SP 是标准实践ADV 是建议性文件TR 是技术报告。TR 的定位是把某个问题的背景、数据、测试思路讲清楚而不是规定你产线上必须怎么做。21.0 是报告序列号小数点后的 .0 表示这是该主题下的第一个主版本后续如果主题拆分会出现 21.1、21.2。01 是版次写法是文件号-版次-年份同一文件号下第一版文本就是 01。2018 是版本年份指这一版通过的年份既不是印刷年份也不是你手上 PDF 的下载时间。2.2 为什么 TR 不能直接当验收依据这是最容易出事的地方。审核方问你们的腕带电阻上限定多少你回一句技术报告里写了对方大概率追问一句那是标准还是报告常见的做法是分三层处理管理程序、验收判据、合同条款引用 S 或 STM 类文件或者引用你们自己的受控规范。技术报告用来支撑为什么这么定放进培训材料、风险评估、内部技术备忘。确实要把报告里的方法固化进内部规范时写法是参照 ANSI/ESD TR21.0-01-2018 相应条款的方法本厂规定……把判据落成自己的数字而不是直接抄报告结论当红线。还有一点要留意TR 的条款通常是描述性的可以采用建议评估这类措辞多直接搬进验收文件会在语法上就站不住。2.3 用脚本核对内部文件里的引用格式与版本年份内部 ESD 管理文档一多引用格式就会乱有的写 ESD TR21.0有的把年份漏了有的把技术报告写进了验收段落。写个脚本一次性扫出来比人工翻快得多。import re, pathlib # ESD Association 文件号六段格式机构 / 类型 / 编号-版次-年份 PAT re.compile(rANSI/ESD\s(TR|S|STM|SP|ADV)\s*(\d(?:\.\d)?)-(\d{2})-(\d{4})) for p in pathlib.Path(esd_docs).rglob(*.md): for lineno, line in enumerate(p.read_text(encodingutf-8).splitlines(), 1): for m in PAT.finditer(line): kind, num, rev, year m.groups() # 技术报告出现在验收语境需要人工复核引用是否恰当 if kind TR and (验收 in line or 判据 in line): print(f{p.name}:{lineno} TR 出现在验收语境 - {m.group(0)}) # 年份明显偏旧的引用挑出来提示核对是否有新版 if int(year) 2018: print(f{p.name}:{lineno} 引用版本偏旧 - {m.group(0)})参数说明正则里(\d(?:\.\d)?)同时兼容 21 和 21.0 两种写法-(\d{2})-锁死两位版次号避免把年份前缀误吞进来。分组顺序跟六段编号一一对应将来格式调整只改正则一处。实际跑的时候TR 出现在验收语境这类命中通常不多但每一条都值得看一眼。字段含义常见误读落地影响ANSI批准环节当成国际标准合同引用要写全 ANSI/ESD 编号ESD发布机构缩写与同名缩写混淆检索时加 association 或 TR 收窄TR技术报告当成强制标准不能直接作验收判据21.0报告序列号当成版本号版本看版次和年份01版次经常被忽略受控文件里要写到 012018版本年份当成下载日期版本比对以此为锚提示受控文件里的引用格式建议固定写成完整六段ANSI/ESD TR21.0-01-2018一个字段都别省年底审核对账时省事。3. 把 ANSI/ESD TR21.0-01-2018 变成可复制文字判定、提取、OCR 三条路3.1 先判定文本型 PDF 还是扫描件很多人一上来就装 OCR 工具结果在一份本来就是文本型的文件上白跑二十分钟。先用三条命令定性。# 看有没有嵌入字体输出非空表通常说明存在文本层 pdffonts ANSI-ESD-TR21.0-01-2018.pdf # 直接抽第一页文字能出词说明可复制 pdftotext -f 1 -l 1 ANSI-ESD-TR21.0-01-2018.pdf - | head -40 # 看每页是不是只有一张覆盖整页的大图 pdfimages -list ANSI-ESD-TR21.0-01-2018.pdf | head -20pdftotext末尾那个-是把结果打到标准输出不落盘。如果抽出来只有空白或者零星几个字符基本可以往扫描件方向走。pdfimages -list每页只有一条记录且尺寸接近整页那就实锤了。现象判定处理路线pdffonts 有嵌入字体pdftotext 出正常英文文本型pdftotext -layout 直接出稿pdffonts 空表pdfimages 每页一张大图扫描型pdftoppm 加 tesseractpdffonts 有字体抽出来却是菱形问号缺 ToUnicode 映射走第 4 章的映射修复部分页正常、部分页纯图混合型逐页判定分开处理3.2 文本型 PDF 的整篇提取# -layout 尽量保留原始版面带表格的标准文件优先用 pdftotext -layout -enc UTF-8 ANSI-ESD-TR21.0-01-2018.pdf tr21.txt # 先抽一小段验证效果再跑全篇 pdftotext -layout -f 5 -l 12 -enc UTF-8 ANSI-ESD-TR21.0-01-2018.pdf tr21_p5_12.txt参数说明-layout按页面坐标重排空格表格里同一行的单元格不会被拆散代价是行尾会留一堆多余空格后面清洗时统一处理。-enc UTF-8明确指定输出编码省得默认编码在你本地终端里变成另一种乱码。-f和-l是起止页码几十页的文件先抽十来页看效果比全篇跑完再改省时间。3.3 用 PyMuPDF 做带分页标记的提取纯命令行出稿快但要清页眉页脚、要保留分页定位脚本更灵活。import fitz # PyMuPDF import re doc fitz.open(ANSI-ESD-TR21.0-01-2018.pdf) out [] for pno in range(doc.page_count): page doc[pno] # text 模式保留基本阅读顺序比 rawdict 轻量得多 txt page.get_text(text) # 清掉单独成行的页眉页脚文件号、页码 txt re.sub(r^\s*(ANSI/ESD TR21\.0-01-2018|Page \d|\d{1,3})\s*$, , txt, flagsre.M) out.append(f\nPAGE {pno1}\n{txt}) open(tr21_clean.txt, w, encodingutf-8).write(.join(out)) # 字符数异常低的页大概率是图片页逐页体检 for pno in range(doc.page_count): n len(doc[pno].get_text(text).strip()) if n 200: print(f第 {pno1} 页字符数仅 {n}需要确认是否为图片)逻辑说明get_text(text)走文本层速度比 OCR 快几个数量级。正则那行专门清页眉页脚标准类文件几乎每页都重复文件号和页码不清掉会污染后面的全文检索和去重。保留PAGE n分页标记是为了后面定位条款时能反查页码。最后那段字符数体检很实用——一份几十页的文件里混进两三页扫描图是常事肉眼翻很难发现。3.4 扫描件的 OCR 路线与参数取值确认是扫描件之后按页面渲染成图再识别。# 300 dpi 灰度转图体积和精度比较平衡 pdftoppm -r 300 -gray -png ANSI-ESD-TR21.0-01-2018.pdf page # 逐页识别标准文件基本是英文 for f in page-*.png; do tesseract $f ${f%.png} -l eng --psm 6 done参数说明-r 300是扫描标准文件的常见下限再低会让小字号脚注糊掉再往上耗时和体积增长很快。-gray转灰度纯文字页没有精度损失文件体积能小不少。--psm 6假设整页是一块连续文本适合正文连续的标准文件如果版面分栏明显先试默认值再考虑--psm 1让引擎自己做版面分析。表格页建议单独拿出来处理OCR 出来的表格线会变成一堆竖线需要人工核对。注意OCR 结果务必和原页逐段抽查。数字类内容风险最高1.0×10^9被识别成1.0x10°这类错误在参数表里几乎必然出现。4. 可复制文字里的菱形问号乱码ToUnicode 映射缺失的探测与修复4.1 UFFFD 是怎么产生的从 PDF 里复制文字出菱形问号根子上不是编码问题是映射问题。PDF 里的文字由字形组成每个字形在当前字体下有一个编码。要让阅读器知道这个字形对应 Unicode 里的哪个字符PDF 需要一张 ToUnicode CMap。有些文件在生成或再加工过程中没写这张表阅读器拿到字形却查不到对应码点就统一吐出 UFFFD也就是那个菱形问号。这跟UTF-8 文件被当成 ANSI 打开是两回事只是外观相似。区别在于缺 ToUnicode 时用任何工具复制都是乱码pdftotext 出来的也乱纯粹编码误判时pdftotext 出来的内容是正常的只是在你本地编辑器里显示不对。先分清是哪种能省掉一大圈无效尝试。4.2 用 PyMuPDF 探测字体编码状态import fitz doc fitz.open(ANSI-ESD-TR21.0-01-2018.pdf) for pno in (0, 1, 2): page doc[pno] print(f--- page {pno1} ---) for f in page.get_fonts(fullTrue): # 字段顺序: xref, ext, type, basefont, name, encoding, ... xref, ext, ftype, basefont, name, encoding f[:6] print(fbase{basefont:35s} type{ftype:8s} enc{encoding}) # rawdict 保留每个字形的坐标和字符坐标正常而字符是 \ufffd 就是映射缺失 d doc[0].get_text(rawdict) for blk in d[blocks][:1]: for line in blk.get(lines, [])[:1]: for span in line[spans][:1]: for ch in span[chars][:8]: print(repr(ch[c]), round(ch[bbox][0], 1))逻辑说明get_fonts里的encoding字段能直接反映阅读器为这个字体推断出的编码。常见的坑是同一页混着好几个子集字体名字带前缀其中一部分有映射、一部分没有。rawdict保留每个字形的坐标和字符坐标正常而字符是\ufffd就实锤了。如果段落里正常字和乱码字混着把这一段逐字符打出来通常能发现乱码集中在某几个字体子集上而不是整页都坏。4.3 三条修复路线怎么选字体状态pdftotext 输出rawdict 字符修复路线有 ToUnicode正常正常 Unicode无需处理无 ToUnicode全为 UFFFD坐标正常、字符为 \ufffd自建字形映射或回落 OCR子集字体部分缺映射正常与乱码混杂乱码集中在少数子集定位子集后单独建映射无文本层空无 chars直接走 OCR路线一是自建字形映射适合坏字符只有几十个的情况import fitz doc fitz.open(ANSI-ESD-TR21.0-01-2018.pdf) page doc[3] count 0 for blk in page.get_text(rawdict)[blocks]: for line in blk.get(lines, []): for span in line[spans]: for ch in span.get(chars, []): if ch[c] \ufffd: count 1 # 打印坐标配合渲染图逐个人工辨认 print(坏字符, round(ch[bbox][0], 1), round(ch[bbox][1], 1)) print(本页坏字符数:, count)拿到坏字符的坐标之后用page.get_pixmap(dpi200)渲染这一页人眼对照坐标把字形读出来建一张字形号到字符的小映射表。坏字符上百就别硬扛走路线三更划算。路线二是换引擎交叉验证。同一份 PDF 在不同提取引擎下表现不一样缺映射时尤其明显。常见的做法是同一页分别用pdftotext -layout、PyMuPDF 的text和words模式各抽一遍对比字符数和可读字符占比挑可读占比最高的那版做初稿再用原页校对。别把这个选择写死换一份文件结论可能就反了。路线三直接回落 OCR适合映射彻底丢失的文件# 已有文本层但乱码时用 --force-ocr 强制覆盖 ocrmypdf -l eng --output-type pdfa -r 300 --force-ocr tr21_in.pdf tr21_ocr.pdf参数说明--output-type pdfa输出归档格式适合内部长期留存-r 300渲染精度与前面保持一致--force-ocr是关键原文件已有文本层但内容不可用时必须加否则工具会认为不需要识别直接跳过。4.4 编码归属导致的二次显示问题如果 pdftotext 出来的文件本身没问题只是在你机器上打开显示成乱码那是纯编码归属问题处理起来简单很多# 先查真实编码别信文件名和扩展名 file -i tr21.txt # 确认不是 UTF-8 再转换方向别写反 iconv -f GB18030 -t UTF-8 old.txt -o new.txtfile -i的判断不能全信中文内容有时候会被猜成别的编码。稳妥做法是看文件开头有没有 BOM再用十六进制视图抽查几个非 ASCII 字节的序列。这一步处理的是自己加工时引入的批注和备注标准正文本身走到这一步基本已经没问题了。5. 让 ANSI/ESD TR21.0-01-2018 的文本可被检索条款锚点、参数检索与版本比对5.1 给每条条款打锚点提取出来的纯文本最大价值是能被检索。前提是每条条款都有唯一且稳定的标记我一般会在清洗脚本里补这一步。import re text open(tr21_clean.txt, encodingutf-8).read() # 把形如 5.2.1 或 A.3 的条款号提到行首并加统一锚点 anchored re.sub( r(?m)^\s*((?:\d\.){1,3}\d|[A-Z]\.\d(?:\.\d)*)\s, rCLAUSE \1 , text, ) open(tr21_anchored.txt, w, encodingutf-8).write(anchored) print(anchored.count(CLAUSE), 条条款已打锚)参数说明(?:\d\.){1,3}\d覆盖 1 / 1.1 / 1.1.1 / 1.1.1.1 四种层级标准文件的条款号一般最深到四级[A-Z]\.\d兜住附录里的 A.1、B.2.3 这类编号(?m)让^匹配每一行的行首。打锚之后条款号和正文之间有个固定分隔符后面无论用什么工具切片都不会把条款号切掉。5.2 用 ripgrep 做参数检索# 找所有涉及电阻、电压、量纲的行带条款上下文 rg -n --no-heading -C 1 CLAUSE|(ohm|volt|10\^) tr21_anchored.txt hit.txt # 只列条款标题行快速得到一份条款清单 rg -n --no-heading ^CLAUSE tr21_anchored.txt | head -80-C 1输出前后各一行上下文条款号和它下面的数值经常不在同一行这个参数能兜住。--no-heading去掉每次的文件名头几十上百条命中时输出干净很多。第二条命令产出的条款清单可以直接贴进内部 ESD 管理文件的索引比手工整理省大量时间。5.3 版本升级时的差异比对这类文件每隔几年会出新版你手上的引用可能就失效了。把两个版本的可复制文本归一化之后做行级比对能快速定位改动。# 压掉行内连续空白再比避免表格空格差异刷屏 awk {$1$1};1 tr21_old.txt old.norm awk {$1$1};1 tr21_new.txt new.norm diff -u --ignore-all-space old.norm new.norm tr21.diff wc -l tr21.diffawk {$1$1};1把每行内部连续空白压成一个空格并去掉首尾空白这样表格里多打两个空格不会被误判成实质修改。真正的数值变动在 diff 里通常显示成成对的/-行扫一眼就能挑出来。提示比对之前先把两份文件的页眉页脚清干净否则每页一行的文件号差异会把输出刷满真正有意义的改动被埋掉。比对结果落成一张变更清单之后把受影响的那几条同步到内部受控文件的引用条目里编号后面的版次和年份一并更新别在同一份文档里留下混着两个年份的引用。本文还有配套的精品资源点击获取
返回列表