強(qiáng)調(diào)檢測(cè)原理與 Golden Test 剖析(issue 7803))
Pandoc AsciiDoc 寫入器詞內(nèi)強(qiáng)調(diào)檢測(cè)原理與 Golden Test 剖析issue #7803【免費(fèi)下載鏈接】pandocUniversal markup converter項(xiàng)目地址: https://gitcode.com/gh_mirrors/pa/pandoc本文以 Pandoc 倉(cāng)庫(kù)中的回歸測(cè)試用例 test/command/7803.md 為切入點(diǎn)深入剖析 AsciiDoc 寫入器writer在 HTML → AsciiDoc 轉(zhuǎn)換中如何判斷詞內(nèi)強(qiáng)調(diào)intraword emphasis并據(jù)此決定使用單下劃線_還是雙下劃線__作為強(qiáng)調(diào)定界符。讀完本文你將掌握 AsciiDoc 輸出中強(qiáng)調(diào)標(biāo)記的選型規(guī)則、inlineListToAsciiDoc中基于isSpacy的相鄰內(nèi)聯(lián)元素掃描算法以及 Pandoc 命令測(cè)試golden test的編寫與運(yùn)行機(jī)制能夠自行分析、驗(yàn)證乃至擴(kuò)展這一類格式轉(zhuǎn)換邊界行為。測(cè)試用例概覽一段 HTML 列表的轉(zhuǎn)換test/command/7803.md 是 Pandoc 命令測(cè)試套件中的一個(gè)回歸測(cè)試regression test文件整體是一個(gè) fenced code block其內(nèi)容格式由 test/Tests/Command.hs 的模塊注釋明確定義% pandoc -f html -t asciidoc ul lia hrefx.htmiXx/i/ai,/i ... /ul ^D * link:x.htm[_Xx_]_,_ ...解析規(guī)則為第一行%之后是待執(zhí)行的 shell 命令中間若干行作為該命令的 stdin 輸入以單獨(dú)一行^D標(biāo)記 stdin 結(jié)束之后的每一行是期望的 stdout 輸出若期望出現(xiàn) stderr 輸出需在每行前加2前綴若期望非零退出碼則末尾追加 exitcode。運(yùn)行時(shí)test/Tests/Command.hs 中的execTest會(huì)通過(guò)shell調(diào)用test-pandoc --emulate見pandocToEmulate將輸入喂給 pandoc 進(jìn)程再把實(shí)際輸出與期望輸出做 golden 比對(duì)。因此7803.md本身就是一個(gè)輸入 期望輸出的完整規(guī)范記錄了該場(chǎng)景下 HTML 讀取器與 AsciiDoc 寫入器協(xié)作后的既定行為。該測(cè)試對(duì)應(yīng)的代碼修復(fù)記錄在 changelog.mdAsciiDoc writer: Improve detection of intraword emphasis (#7803).提交ea7458228AsciiDoc writer: improve detection of intraword emphasisCloses #7803只改動(dòng)了兩處一行實(shí)現(xiàn)代碼加一個(gè)測(cè)試文件——正是本用例。待解決問(wèn)題的本質(zhì)單下劃線與雙下劃線的取舍在 AsciiDocAsciidoctor 方言中_text_表示斜體強(qiáng)調(diào)而__text__表示詞內(nèi)強(qiáng)調(diào)intraword emphasis即當(dāng)被強(qiáng)調(diào)的文本緊貼在普通單詞字符之間、不與其他單詞分隔時(shí)使用的形式。例如A__b__C中b是詞內(nèi)強(qiáng)調(diào)若寫成A_b_C則不會(huì)被解析為強(qiáng)調(diào)而是原樣輸出。Pandoc 內(nèi)部文檔模型并不區(qū)分詞內(nèi)與詞間強(qiáng)調(diào)——HTML 中i就是i。因此 AsciiDoc 寫入器必須根據(jù)被強(qiáng)調(diào)內(nèi)容在相鄰內(nèi)聯(lián)元素序列中的位置自行推斷只有當(dāng)強(qiáng)調(diào)內(nèi)容緊鄰著非分隔字符比如緊跟在Xx之后時(shí)才需要升級(jí)為__...__否則使用普通的_..._。源碼實(shí)現(xiàn)inlineListToAsciiDoc與isSpacy判定核心邏輯位于 src/Text/Pandoc/Writers/AsciiDoc.hs。寫入器用WriterState中的一個(gè)intraword :: Bool字段src/Text/Pandoc/Writers/AsciiDoc.hs#L65-L77在遞歸過(guò)程中傳遞當(dāng)前內(nèi)聯(lián)元素是否處于詞內(nèi)位置這一狀態(tài)。inlineListToAsciiDoc對(duì)相鄰內(nèi)聯(lián)元素y : x : xs分三種情況處理若y結(jié)尾不是分隔符isSpacy End y為 False則說(shuō)明x緊跟在一個(gè)詞內(nèi)處理x時(shí)需要開啟intraword即withIntraword $ inlineToAsciiDoc opts x否則若x開頭不是分隔符isSpacy Start x為 False說(shuō)明y處于詞內(nèi)位置處理y時(shí)開啟intraword其余情況兩者都不處于詞內(nèi)。withIntrawordsrc/Text/Pandoc/Writers/AsciiDoc.hs#L604-L605在求值前后分別setIntraword True與setIntraword False實(shí)現(xiàn)局部狀態(tài)切換。isSpacy的判定規(guī)則src/Text/Pandoc/Writers/AsciiDoc.hs#L586-L599如下Space、LineBreak、SoftBreak一律視為分隔符Str的末尾/開頭字符若是標(biāo)點(diǎn)isPunctuation或空白isSpace則該側(cè)視為分隔符Link、Image的結(jié)尾視為分隔符isSpacy End (Link{}) True其余情況——關(guān)鍵所在——在修復(fù)后一律視為非分隔符isSpacy _ _ True。修復(fù)的實(shí)質(zhì)把默認(rèn)值從分隔改為不分隔提交ea7458228對(duì)實(shí)現(xiàn)的改動(dòng)只有一行src/Text/Pandoc/Writers/AsciiDoc.hs中inlineListToAsciiDoc的isSpacy函數(shù)isSpacy Start (Str xs) | Just (c, _) - T.uncons xs isPunctuation c || isSpace c - isSpacy _ _ False isSpacy _ _ True改動(dòng)前未知類型的內(nèi)聯(lián)元素默認(rèn)被當(dāng)作分隔符False導(dǎo)致Link、Emph等復(fù)雜元素開頭/結(jié)尾相鄰的強(qiáng)調(diào)被誤判為詞間輸出普通_..._改動(dòng)后默認(rèn)按非分隔符處理True只有明確命中空白、標(biāo)點(diǎn)或鏈接結(jié)尾時(shí)才按分隔符處理。這使鏈接、圖片等內(nèi)聯(lián)對(duì)象與強(qiáng)調(diào)文本相鄰時(shí)能更準(zhǔn)確地識(shí)別詞內(nèi)強(qiáng)調(diào)。逐行驗(yàn)證期望輸出現(xiàn)在把測(cè)試輸入與輸出逐項(xiàng)對(duì)應(yīng)驗(yàn)證isSpacy的推斷邏輯#HTML 輸入片段AsciiDoc 輸出判定依據(jù)1aiXx/i/ai,/ilink:x.htm[_Xx_]_,_Link結(jié)尾為分隔Xx非詞內(nèi)用_Xx_,后接/li換行獨(dú)立成_,_2i,,/i_,,_連續(xù)兩個(gè)標(biāo)點(diǎn)各自獨(dú)立強(qiáng)調(diào)3i1/i_1_數(shù)字前無(wú)緊鄰詞字符41i1/i1__1__前置1為詞字符1處于詞內(nèi) →__1__5ibcd/i_bcd_獨(dú)立強(qiáng)調(diào)6aibcd/ia__bcd__緊鄰a詞內(nèi) →__bcd__7aibcd/iea__bcd__e前后均緊鄰詞字符詞內(nèi)強(qiáng)調(diào)8aXx/a i,/ilink:x.htm[_Xx_] _,_Link結(jié)尾分隔 Space分隔i,/i前有空格9,i,/ilink:x.htm[_Xx_],_,_前一個(gè),為標(biāo)點(diǎn)分隔10aXx/ai,/ilink:x.htm[Xx]_,_鏈接文本無(wú)強(qiáng)調(diào),獨(dú)立強(qiáng)調(diào)從源碼看可推斷出判定機(jī)制如下Link的結(jié)尾isSpacy End (Link{}) True與Str中的標(biāo)點(diǎn)字符、空白字符一樣被視為分隔符反之字母、數(shù)字等普通字符isPunctuation與isSpace均為 False視為詞字符緊鄰它們的強(qiáng)調(diào)內(nèi)容便進(jìn)入intraword分支輸出__...__。這正是第 4、6、7 行與第 1、5 行產(chǎn)生差異的原因。關(guān)聯(lián)機(jī)制Emph與Strong的定界符選擇isSpacy推斷出的intraword狀態(tài)最終由 inlineToAsciiDoc 消費(fèi)inlineToAsciiDoc opts (Emph lst) do contents - inlineListToAsciiDoc opts lst isIntraword - gets intraword let marker if isIntraword then __ else _ return $ delimited marker marker contentsEmph斜體詞內(nèi)用__詞間用_Strong加粗詞內(nèi)用****詞間用**Underline、Strikeout、Superscript、Subscript、SmallCaps則固定使用[...]#/^...^/~...~/[smallcaps]#...#等定界符不隨詞內(nèi)狀態(tài)變化。delimited marker marker contents會(huì)確保定界符與內(nèi)容之間保持正確的空白關(guān)系最終形成測(cè)試中形如1__1__、a__bcd__e的輸出。延伸同系列的相鄰修復(fù)#7803并非孤例changelog 顯示 AsciiDoc 寫入器的強(qiáng)調(diào)/轉(zhuǎn)義處理經(jīng)歷過(guò)一系列迭代#8070修復(fù)鏈接文本中的逗號(hào)逗號(hào)會(huì)觸發(fā) AsciiDoc 屬性解析需替換為#44;數(shù)字實(shí)體相關(guān)邏輯見 inlineToAsciiDoc 中的fixCommas#8525/ 后續(xù)調(diào)整鏈接尾跡link trail的字符范圍從僅 ASCII 字母擴(kuò)展為除 CJK 統(tǒng)一表意文字區(qū)間外的所有字母以兼容西班牙語(yǔ)等語(yǔ)言#8936asciidoc格式轉(zhuǎn)向以 Asciidoctor 解析的現(xiàn)代方言為目標(biāo)asciidoctor成為廢棄同義詞writeAsciiDoctor。這些修復(fù)共同塑造了當(dāng)前 src/Text/Pandoc/Writers/AsciiDoc.hs 中escapeString、isSpacy等函數(shù)的復(fù)雜行為而test/command/目錄下的編號(hào)測(cè)試文件則構(gòu)成了保障這些行為不回歸的防線。如何運(yùn)行與擴(kuò)展該測(cè)試命令測(cè)試統(tǒng)一由 test/test-pandoc.hs 中的Tests.Command.tests驅(qū)動(dòng)測(cè)試分組見pandoc tests。常規(guī)執(zhí)行方式# 構(gòu)建并運(yùn)行全部測(cè)試含 command 測(cè)試 cabal test pandoc # 或使用 Makefile 目標(biāo) make test若要單獨(dú)驗(yàn)證本用例可用等價(jià)命令手工復(fù)現(xiàn)pandoc -f html -t asciidoc test/command/7803.md 的輸入部分新增類似回歸測(cè)試時(shí)只需在 test/command/ 下新建NNNN.md文件按% 命令 / stdin / ^D / 期望輸出的格式書寫即可無(wú)需改動(dòng)測(cè)試框架代碼——這正是 test/Tests/Command.hs 設(shè)計(jì)的可擴(kuò)展性所在。小結(jié)test/command/7803.md以最小化的 HTML 列表輸入完整鎖定了 AsciiDoc 寫入器詞內(nèi)強(qiáng)調(diào)檢測(cè)的 10 種邊界情形是理解isSpacy判定算法與intraword狀態(tài)機(jī)的最佳樣例。其背后的修復(fù)默認(rèn)值由分隔改為不分隔提醒我們?cè)诟袷睫D(zhuǎn)換器中未顯式匹配即視為默認(rèn)的策略選擇往往正是決定輸出是否符合目標(biāo)格式方言語(yǔ)義的關(guān)鍵。【免費(fèi)下載鏈接】pandocUniversal markup converter項(xiàng)目地址: https://gitcode.com/gh_mirrors/pa/pandoc創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考