我太小看這個分句功能了。
結果一直忙到晚上十點多,
好不容易才把程式碼初步搞定。
話說這個 html 的分句功能,
最難纏的就是各式各樣的 html 標籤。
這些標籤功能繁多,各有不同的特性。
(若以 nodeType 來區分,可參考 MDN 的文件)
不過在分句的考量上,大致可分成兩大類。
// 行內標籤:參見 https://www.w3schools.com/html/html_blocks.asp
inline_tags = [
'span', 'a', 'em', 'b', 'i', 'big', 'small',
'br', 'strong', 'sub', 'sup', 'tt', 'abbr',
'img',
'acronym', 'bdo', 'dfn', 'kbd', 'map',
'object', 'output', 'q', 'samp', 'time',
'var', 'cite',
'nobr',
];
// 區塊標籤:參見 https://www.w3schools.com/html/html_blocks.asp
block_tags= [
'html', 'head', 'body',
'section', 'nav', 'main', 'footer',
'div', 'table', 'thead', 'tbody', 'tfoot',
'tr', 'ul', 'ol', 'hr', 'colgroup', 'col', 'dl',
'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'caption', 'th', 'td', 'li', 'dd', 'dt',
'form', 'header',
'address', 'article', 'aside', 'blockquote',
'canvas', 'fieldset',
'figcaption', 'figure',
'label',
'button', 'input', 'select', 'textarea',
// txt 檔案若在瀏覽器中開啟,其內容會被包在 pre 裡頭。。。
'pre',
// 下面是 Google Cloud Document 用到的一些特殊 tag
'devsite-header', 'devsite-content', 'devsite-toc',
'devsite-footer-linkboxes', 'devsite-footer-utility',
'devsite-language-selector', 'devsite-select',
// 下面這些註解起來的,都會變成不明 tag,不會進行分句處理
// 'code',
// 'script',
// 'video',
// 'noscript',
];
這些 HTML 標籤還有另一個很難處理的特性,
那就是大部分標籤通常會包住另一堆標籤,
形成層層相嵌的 DOM 樹狀結構。
在進行分句時主要針對的是文字,
但 HTML 所有的標籤會形成 DOM 這樣的結構。
為了對付這種一層包著另一層的結構,
我採用了遞迴的做法。
這樣的做法也許會犧牲一點效能,
但程式碼會簡潔很多,
讀起來也比較容易理解。
為了進行分句,
我創造了一個全新的 sent 標籤。
在每一個句子的前後,
都用這個 sent 標籤包了起來。
這麼做有很多好處。
實際上不過分的說,
將來有很多很厲害的功能,
都是靠它來實現的。
所以我另外針對這個 sentTag.js,
建立了一個獨立的小專案:
git clone https://github.com/betterTrans/sentTag
這個小專案也歡迎大家一起參與,
讓 HTML 的分句功能越來越棒囉 ^_^
我們只要把這個 sentTag.js 複製到
之前 betterTranslation 目錄裡的 js 子目錄,
然後修改一下 manifest.json,
把 sentTag.js 添加到 content_scripts 的列表中:
"content_scripts": [ {
"matches": ["<all_urls>"],
"js": [
"js/sentTag.js",
"js/content.js"
]
} ]
最後在 content.js 按下 Alt+1 的程式區塊中,
添加一行程式碼:
if (e.altKey && e.key=='1') {
// 備份原始 HTML
body0 = document.body.innerHTML;
// 分句
document.body.innerHTML = addSentTag2HTML(document.body.innerHTML);
}
重新載入外掛之後,按下 Alt+1,
整個網頁就完成分句的工作了。。。
什麼?看不出來?
沒錯,雖然我們完成了分句,
添加了許多 sent 標籤,
整個網頁的外觀卻不會有任何的變動。
某種程度來說,
我們就是希望這個分句的動作,
不要影響到原本的網頁內容。
但這個分句完成的網頁,
究竟有什麼用途呢?
我們今天就先小試身手一下,
為每一個 sent 標籤加上 title 的屬性吧。
只要在剛才分句的程式碼下面,
添加一小段程式碼:
// 添加 title 屬性
document.querySelectorAll("sent").forEach((node)=>{
node.title = node.textContent;
});
是的,這樣就完成了。
程式修改完之後,別忘了重新載入外掛。
重新載入之後,你只要再次按下 ALT+1,
接著移動到網頁的任何一個句子上,
都會自動浮現出這個句子的原文了。
有了 sent 標籤之後,
我們就能以句子為單位,
進行各式各樣的處理了。
明天我們就來好好善用這個 sent 標籤,
看看能玩出什麼樣的花招囉。