歡迎您光臨本站 註冊首頁

Gnus 中的編碼設定

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  

用了一段時間 Gnus,對 Gnus 中的各種編碼設定有了些了解,寫出來與大家分享。

廣告結束

閑話結束

Gnus 是構建在 Emacs 之上的,自然也就利用了 Emacs 超強的多國語言編碼支持。
所以如果你有一封亂碼的郵件,如果 Gnus 看不了的話,那麼估計賣糕的也不會有辦
法了。

為了處理各種編碼的郵件,gnus 提供了很多可以設置的變數。不過變數多了也會帶
來麻煩,如果你設置不好的話,就有可能開槍打中自己的腳。

** 先談談郵件編碼

郵件可以分為兩個部分: header 和 body。比較文明的郵件會在 header 的
`Content-Type' 這一行中用 MIME 說明郵件採用了什麼編碼。而不文明的郵件則缺
少這種說明,對於只有英文的郵件,這樣做不會有問題,而對於包含中文的郵件,
就有可能這是導致亂碼,小比爾的 Outlook Express 就喜歡發出這種郵件,一些
webmail 也經常幹這種事。

另外,在郵件頭中,還可以指定郵件的傳輸編碼。如果郵件的內容都是7位的
us-ascii字元,就不會出現什麼傳輸編碼的問題,但是因為漢字的編碼一般都是8
位的,而有些郵件網關只能傳輸7bit字元,最高位作其它用途了,所以就出現了
base64, quoted-printable 等把8位字元轉換成7位編碼進行傳輸的編碼方案。
郵件的傳輸編碼可以在郵件頭中用 `Content-Transfer-Encoding' 指出來。

我們可以讓 Gnus 把 `Content-Type' 和 `Content-Transfer-Encoding' 欄位顯示
出來:

(add-hook 'gnus-startup-hook
'(lambda ()
(setq gnus-visible-headers
(concat "^User-Agent:\\|^Content-Type:\\|"
"Content-Transfer-Encoding:\\|"
"^X-mailer:\\|^X-Newsreader:\\|^X-Sender:\\|"
gnus-visible-headers))))

這樣我們就可以看到郵件採用了什麼編碼(順便還可以看到對方用的是什麼客戶端
軟體),如果郵件指定了編碼,你就會在郵件頭部看到這一行:

Content-Type: text/plain; charset=GB18030

如果郵件指定了傳輸編碼,就可以看到這樣一行:

Content-Transfer-Encoding: base64

** Gnus 中與編碼有關的變數

需要說明的是,大多數情況下,郵件都是比較文明的,在 Content-Type 欄位已經
說明了郵件採用的編碼,那麼 Gnus 將自動按指定的編碼顯示郵件。除非 Emacs 本
身就不支持這種編碼,否則是不會出現亂碼的。

一個常見情況就是使用 Emacs21 或 Emacs22,而不安裝 mule-gbk,要知道
Emacs21/22 本身就不支持 GBK 和GB18030,這樣對於 charset=gbk, 或
charset=gb18030 的郵件出現亂碼就不奇怪了。所以,如果你使用的是 Emacs21 或
Emacs22, 趕緊去下載 mule-gbk 裝上吧。注意,對於 Emacs22,mule-gbk 的設置
中一定要加上這一句:

(utf-translate-cjk-load-tables)

否則 Emacs22 無法進行 gbk <--> utf-8 的轉換,而 gnus 是先用 utf-8 編寫郵
件,再轉換成指定的編碼發出去,如果不加上這句設置,就會出現只能發 utf-8
的郵件,不能發 gbk 郵件的怪現象。

下面討論的設置適用於 Emacs22+mule-gbk 和 Emacs23。

如果郵件中已經用 Content-Type 和 Content-Transfer-Encoding 指定了編碼,
那麼 gnus 將忠實地採用這些編碼處理郵件,這時是不應該出現亂碼的。所以,我
們所做的設置基本上都是為了對付那些搗亂的,不指明編碼的郵件。

現在我們來看看 gnus 中與編碼設置有關的變數。這些變數可以分為兩種類型,一
種是與郵件內容有關的,另一種是與組名(group name)有關的。

** 與郵件內容有關的變數

*** gnus-default-charset

這個變數指定查看郵件所用編碼的默認值(對於未指定編碼的郵件)。但是這
個變數的會被下一個變數(gnus-group-charset-alist)覆蓋。如果不設置這個
變數,它的值將由 `current-language-environment' 確定。

例如:(setq gnus-default-charset 'gbk)

*** gnus-group-charset-alist

這個變數根據組名確定本組的默認編碼。設置這個變數時我們要給出一個
(regexp charset) 對,其中 regexp 時匹配組名的正則表達式,charset 是制
定的編碼。在這個變數的默認設置中,我們可以查到如下內容:

("\\(^\\|:\\)hk\\>\\|\\(^\\|:\\)tw\\>\\|\\" cn-big5)
("\\(^\\|:\\)cn\\>\\|\\" cn-gb-2312)

可以看出,對於以 hk 或 tw 開頭(或者組名中包含 :hk 或 :tw)的組,採用
big5編碼。而對於以 cn 開頭或組名中包含 :cn 的組採用 cn-gb-2312 的編
碼。

因為現在 gbk 比 gb2312 應用更廣泛,所以我們需要更改這個變數的設置:

(add-to-list 'gnus-group-charset-alist
'("\\(^\\|:\\)cn\\>\\|\\" gbk))

這個變數也可以在 group parameter 中以 (charset . gbk) 的方式指定。

*** gnus-summary-show-article-charset-alist

有時候,默認的編碼還不能解決問題,例如,有人把 big5 編碼的郵件投遞到
了 cn 開頭的組裡,而且郵件頭中又沒有編碼設定(插一句,這些郵件一般
都是垃圾郵件),這時就需要手工指定編碼。

(setq gnus-summary-show-article-charset-alist
'((1 . utf-8)
(2 . big5)
(3 . gbk)
(4 . utf-7)))

進行了這種設定以後,我們看到亂碼郵件時就可以用 `1 g' 指定採用 utf-8,
`2 g' 指定big5等等,不過能不能正確解碼就要看你自己猜的對不對了。

** 與組名有關的變數

我們訂閱新聞組時,可以看到有些伺服器上的組名都是英文的,比如在
`news.cn99.com' 這個伺服器中組名都是這樣的:

gnu.emacs.help
cn.comp.os.linux
tw.bbs.os.linux

而有些伺服器的組名卻是包含中文的,比如新帆`news.newsfan.net'的組名:

計算機.軟體.操作系統.FreeBSD
計算機.軟體.操作系統.linux
休閑娛樂.遊戲天地.Diablo

下面兩個變數是為了讓gnus能正確地處理非ascii組名的。

*** gnus-group-name-charset-group-alist

這個變數根據組名確定組名採用的編碼,默認值是`((".*" utf-8))',也就是
默認用 utf-8 處理所有組名。我們可以這樣這樣設置:

(setq gnus-group-name-charset-group-alist
'(("\\.com\\.cn:" . gbk)
("news\\.newsfan\\.net" . gbk)))

這樣所有組名中含有 .com.cn 或 news.newsfan.net 的組,其名稱都採用 gbk
解碼。

不過如果我們把 news.newsfan.net 設置為 native method, 那麼組名中就不
會出現 news.newsfan.net,那麼這個變數就發揮不了作用,怎麼辦呢?可以采
用下面這個變數。

*** gnus-group-name-charset-method-alist

還記得嗎?我們選擇新聞伺服器時是怎麼設定的?對了,我們是通過設置
method 來選擇伺服器的,比如:

(setq gnus-select-method '(nntp "news.newsfan.net"))
(setq gnus-secondary-select-methods '((nnml "")))

這個變數可以根據我們選擇的 method,為來自這個 method 的組設置組名的
編碼。

(setq gnus-group-name-charset-method-alist
'(((nntp "news.newsfan.net") . gbk)))

這樣,所有來自新帆伺服器的組名都採用gbk來解碼。

** 設置發出郵件的編碼: mm-coding-system-priorities

當我們向外發送郵件時,也可以指定編碼,比如我們希望發出的郵件採用gb2312編
碼,就可以這樣設置:

(setq mm-coding-system-priorities '(iso-8859-1 gb2312 utf-8))

這樣,gnus將先試這採用 iso-8859-1 編碼郵件,如果不行就採用 gb2312,實在
不行再採用 utf-8 編碼。

這樣如果你寫了一封純英文的信件,將會採用 iso-8859-1 發出;如果你寫了一封
中文信件,但其中的漢字都在 gb2312 的範圍內,則採用gb2312發出;如果你的信
件中含有gb2312以外的字元,則會被以utf-8編碼發出。

那麼如果想對不同的組採用不同的編碼發信,有辦法實現嗎?可以,通過設置
posting-style 就可以實現。

(setq gnus-posting-styles
'((".*"
(name "Brep")
(address "brep@bogus.com")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 utf-8))))
("^cn\\.comp"
(name "Brep")
(address "brep@smth.org")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 gb2312 utf-8))))
("^tw\\.comp"
(name "Brep")
(address "brep@ptt.cc")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 big5 utf-8))))))

這樣對於 cn.comp 開頭的組,gnus會先嘗試採用gb2312發送郵件,不行再用utf-8,
而對於 tw.comp 開頭的組,會先嘗試採用big5發送郵件,不行再用utf-8。

** 處理有問題的郵件: gnus-newsgroup-ignored-charsets

有些客戶端發出的郵件沒有指定正確的MIME類型,例如本來這封郵件是用 gbk 編
碼的,但是 MIME 類型卻設置成了 x-gbk:

Content-Type: text/plain; charset=x-gbk

這時gnus解碼時會遇到困難,我們可以把這種 MIME 類型加入到
gnus-newsgroup-ignored-charsets 列表中,讓 gnus 採用默認的編碼處理它。

再比如,有些郵件的 MIME 類型是 charset=gb18030, 對於 emacs23,這是沒問題
的,因為 Emacs23 支持 gb18030 編碼。但是 emacs22+mule-gbk 根本就不支持
gb18030,那麼該怎麼辦呢?同樣我們可以把 gb18030 加入
gnus-newsgroup-ignored-charsets 列表中:

(setq gnus-newsgroup-ignored-charsets
'(unknown-8bit x-unknown x-gbk gb18030))

ignored-charsets 也可以在 group parameters 中這樣指定:

(ignored-charsets x-unknown iso-8859-1)

** 指定傳輸編碼:gnus-group-posting-charset-alist

這個變數可以用來設置郵件頭中的 Content-Transfer-Encoding 欄位,為郵件指
定傳輸編碼。這個變數的默認值已經設置的很好了,我從來沒有遇到需要設置這個
變數的情況。

** 不要讓自己發出亂碼的郵件(指定附件文件名和subject的編碼方式)

gnus 默認採用 RFC2231 對附件文件名進行編碼,有些 MUA 無法識別這種編碼。現
在比較流行的方式是採用 RFC2047 對附件文件名進行編碼。可以採用如下設定,讓
gnus 也採用這種方式對文件名進行編碼:

(defalias 'mail-header-encode-parameter 'rfc2047-encode-parameter)

有很多差勁的郵件客戶端無法解碼 quoted-printable 編碼(看到過 subject 中有
很多 `=' 號的亂碼郵件嗎?就是由於這個原因產生的。)為了保證我們發出的郵件
subject 採用 base64 編碼,而不是採用quoted-printable 編碼,最好加上這兩句:

(add-to-list 'rfc2047-charset-encoding-alist '(gbk . B))
(add-to-list 'rfc2047-charset-encoding-alist '(gb18030 . B))

** 參考設置

最後給出一個參考設置吧,適用於 Emacs22+mule-gbk 或者 Emacs23:

(setq gnus-default-charset 'gbk)
(add-to-list 'gnus-group-charset-alist
'("\\(^\\|:\\)cn\\>\\|\\" gbk))
(setq gnus-summary-show-article-charset-alist
'((1 . utf-8)
(2 . big5)
(3 . gbk)
(4 . utf-7)))
(setq gnus-group-name-charset-group-alist
'(("\\.com\\.cn:" . gbk)
("news\\.newsfan\\.net" . gbk)))
(setq gnus-group-name-charset-method-alist
'(((nntp "news.newsfan.net") . gbk)))
(setq gnus-newsgroup-ignored-charsets
'(unknown-8bit x-unknown x-gbk gb18030))

(defalias 'mail-header-encode-parameter 'rfc2047-encode-parameter)
(add-to-list 'rfc2047-charset-encoding-alist '(gbk . B))
(add-to-list 'rfc2047-charset-encoding-alist '(gb18030 . B))

(setq gnus-posting-styles
'((".*"
(name "Brep")
(address "brep@bogus.com")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 utf-8))))
("^cn\\.comp"
(name "Brep")
(address "brep@smth.org")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 gb2312 utf-8))))
("^tw\\.comp"
(name "Brep")
(address "brep@ptt.cc")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 big5 utf-8))))))

(add-hook 'gnus-startup-hook
'(lambda ()
(setq gnus-visible-headers
(concat "^User-Agent:\\|^Content-Type:\\|"
"Content-Transfer-Encoding:\\|"
"^X-mailer:\\|^X-Newsreader:\\|^X-Sender:\\|"
gnus-visible-headers))))

** 不要讓自己發出亂碼的郵件(指定附件文件名和subject的編碼方式)

gnus 默認採用 RFC2231 對附件文件名進行編碼,有些 MUA 無法識別這種編碼。現
在比較流行的方式是採用 RFC2047 對附件文件名進行編碼。可以採用如下設定,讓
gnus 也採用這種方式對文件名進行編碼:

(defalias 'mail-header-encode-parameter 'rfc2047-encode-parameter)

有很多差勁的郵件客戶端無法解碼 quoted-printable 編碼(看到過 subject 中有
很多 `=' 號的亂碼郵件嗎?就是由於這個原因產生的。)為了保證我們發出的郵件
subject 採用 base64 編碼,而不是採用quoted-printable 編碼,最好加上這兩句:

(add-to-list 'rfc2047-charset-encoding-alist '(gbk . B))
(add-to-list 'rfc2047-charset-encoding-alist '(gb18030 . B))
因為這篇文章主要是討論Gnus的編碼問題,所以這裡列出的僅僅是與編碼有關的設置。

# Local Variables:
# mode: org
# coding: utf-8
# End:



[火星人 ] Gnus 中的編碼設定已經有749次圍觀

http://coctec.com/docs/linux/show-post-67585.html