應用程式沒有 http 服務也可以用 oauth2


oauth2 使用者同意受權你的應用程式後,一般都導回參數 redirect_uri 指定的網址, 並把 code 帶進去。 如果你的應用程式(傳統程式、非網頁) 懶得做 http 服務,也可以這樣玩...
 

叫 User 自己把 code 貼到你的程式上,然後程式再拿這個 code 去要 access token。

IIS 的 URL Rewrite 使用: 規則運算式


假設請求網址為 http://www.domain.com.tw/dir/search.aspx?user=sean

這算是自己的筆記吧! IIS 的 URL Rewrite 很好用,但想設定的人可能一頭霧水。Regular Expression 的 Pattern 是要從 http:// 開始、或是 www. 開始、或是 /dir 或 dir 都沒有說明, 每次都會忘記,所以自己做個筆記。址尾是否包含 Query String 也沒說明。


結論:

● 「模式:」填寫 Regular Expression Pattern,此例「^dir/search\.aspx$」是符合的。

● 「重寫 URL:」用 {R:1} ~ 9 當回溯值(Back-reference; 也就是 RegExp 中的括弧順序)。

● 勾「附加查詢字串」會把「?user=sean」加到「重寫 URL」尾端。

讓 YUI DataTable 使用 JSON Data Over XHR 時支援中文 field

原由

YUI 真是個好東西,最近拿它來寫公司的程式。
天殺的! 不知以前是誰把資料庫欄位都用中文命名。
我輸出 JSON 長這樣...


{
 "ResultSet": {
  "Result": [{
   "ID": "1234",
   "姓名": "林洵賢",
   "電話": "1234567890"

... 省略

話說當今瀏覽器 UTF8 編碼的頁面 JavaScript 運作起來是沒什麼問題。
但 YUI 是外國人設計的,用它的 DataSource 抓資料後認為這些以中文為 key 的是壞東西會自動被忽略。


解決

追程式囉! 我原本是用 DataTable 當然從它開始追,追到另一個模組 DataSource 找到了!
我用的是 YUI 2.9 版,修改 \build\datasource\datasource*.js 原始程式,把

[^\w\.\$@]

改成

[^\w\.\$@\u4e00-\u9fa5]

就支援中文 key 了。


或許這篇算是寫給自己的筆記,沒接觸過的應該看沒有。
如果你不幸也在找同樣的解決方案 google 到我,那恭喜你囉,留個言吧!


後記
後來發現欄位排序中文Key也有問題,要修改 datatable*.js 尋找 [^\w\-] 改為 [^\w\-\u4e00-\u9fa5] 即可。

IIS 7.5 Express 多重網站

IIS 7.5 Express 支援多重網站嗎? 官方是不支援這樣的設定的。

微軟出的 IIS 7.5 Express 可以讓舊電腦(XP)安裝最新的IIS版本。想把 XP 內建的 IIS 換成 IIS Express 要有些心理準備。它沒有完整的 GUI 設定介面,所有設定都要用文字編輯器修改設定檔。啟動或停止網站服務也都要用命令列指令來完成。不過裝了它可以讓 XP 擁有如同伺服器最新 IIS 版本的所有功能。

還有個缺點,一次只能只能啟動一個網站,即使設了多個也是只能選其中一個來啟動。畢竟它是設計來當開發用的測試環境。還好 IIS Express 內建 URL Rewrite 模組。有了 URL Rewrite 透過一些小技巧就可以把不同目錄模疑成支援多網站的IIS了。

假設有兩個網域 www.aaa.com 及 www.bbb.com 的 IP 都指到這台電腦。如果想讓

  • 連到 http://www.aaa.com/ 連到網站根目錄下的 /www.aaa.com/
  • 連到 http://www.bbb.com/ 連到網站根目錄下的  /www.bbb.com/


可以透過修改網站 web.config 檔 (沒有的話自行建立放置於網站根目錄)
加入 URL Rewrite 的設定如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rewriteMaps>
                <rewriteMap name="site1" />
            </rewriteMaps>
            <rules>
                <rule name="CanonicalHostNameRule1" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{HTTP_HOST}" pattern="^(.+)$" />
                    </conditions>
                    <action type="Rewrite" url="{C:1}/{R:0}" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

如此一來感覺就像同時啟動兩個虛疑網站囉!

有關 IIS Express 的安裝使用就請客位看官請自行 Google 一下吧!

噗浪備份工具 v2

Plurk Backup v2.0 Beta 1

感謝大家愛用小弟寫的「噗浪備份工具」程式。平常都沒什麼人反映問題,以為沒人在用這程式。這幾天噗浪官網突然改變 Web 介面的一些東西,造成舊程式不能使用。向小弟反映的網友突然爆量,只好先趕出一個 Beta 版。因為沒什麼時間寫 GUI 介面,所以各位就先用這個版本頂著用吧!

從這版開始改用官方 API 重新撰寫資料傳輸程式,我想下載速度應該比以前快。此外,這個版本改變抓資料時登入方式,將不再詢問密碼。如果您是「私密時間軸」的話,請把 http://www.plurk.com/pbu 加入好友,備份完馬上刪除好友即可。

下載 PlurkBackup v2.0 (Beta2): PlurkBackup2Beta2.zip (2.5MB)

讓 Blogger 的「意見回應」可以有「作者回覆」 (最終版)



有很多網友反應【讓 Blogger 的意見回應可以有回覆】那篇,使用 ar.js 檔案需要有自己的 Web 空間,對於初階的網友有點難度。好人做到底,再做一個不用另找網站空間的教學。相信只要一步一步做都能成功的。


照片網誌小幫手 (Flickr to Blogger)


閒閒在家沒事幹,寫了一個網頁小程式。我稱它為「照片網誌小幫手」,它可以幫您把 Flickr 照片以相簿方式刊登在 Blogger 網誌。(效果展示)

它完全用 JavaScript 完成,沒有動用到 Server 端的程式。

網址在 http://s.o4u.com/flog/

大家來玩玩看吧!

雖然 Flickr 雖然每個月都開放上傳空間,但是免費使用者在 Flickr 網頁上最多只可以瀏覽最後的 200 張照片。只要照片網址記得,Flickr 並不會擋住超過200張的照片。因此,結合了網誌的功能後,再也沒有 200 張照片的限制了。

噗浪備份工具

注意: 這是舊版程式,已無法下載噗浪了。請至新版頁面「噗浪備份工具 v2」。



■ 程式版本:v1.1 (3/16/2010 更新)




噗浪 (http://www.plurk.com/) 在台灣算是使用人口最多的微型網誌。它有別於堆特之時間軸設計、以及回覆功能非常受到歡迎。

噗浪客若要查詢稍久以前的噗文,用滑鼠滾時間軸不知要滾到民國幾年。此程式可以將指定期間內自己的噗文全部抓下來。

從 1.0 版閞始,已經可以連同回覆的噗文一起抓下來了。
1.1版增加「分離私噗」功能。
希望您會喜歡,也請您不吝給小弟指教。

這個程式由 Perl 撰寫而成。使用到 CPAN 上的 WWW-Plurk 模組,由於它太久沒維護了已經不太能使用,我有修改到一些。需要我的原始碼可以在這裡下載。


PicasaWeb Perl Module


■ Download/下載 : picasaweb_perl.zip


你在找 Perl 管理 PicasaWeb 的模組嗎? 如果你在 CPAN 上找到 Net::Google::PicasaWeb 覺得很難用,還有功能不全。可以來試試小弟改寫的 Perl 模組。

CPAN 上的 Net::Google::PicasaWeb 並沒有建立相簿、上傳照片等功能。我改寫對岸 董强 的 Google::Picasa。歡迎大家使用。

裡面有幾個簡單的範例,沒什麼教學文件。有心使用的人只好用肉眼看看 Picasa.pm 這個檔案吧!

在 .Net 使用 GDI+ 調整圖片亮度

也就是 RGB 一起調啦!

原始出處


Bitmap origanalImage;
Bitmap adjustedImage;
double brightness = 1.0f; // no change in brightness
double constrast = 2.0f; // twice the contrast
double gamma = 1.0f; // no change in gamma

float adjustedBrightness = brightness - 1.0f;
// create matrix that will brighten and contrast the image
float[][] ptsArray ={
new float[] {contrast, 0, 0, 0, 0}, // scale red
new float[] {0, contrast, 0, 0, 0}, // scale green
new float[] {0, 0, contrast, 0, 0}, // scale blue
new float[] {0, 0, 0, 1.0f, 0}, // don't scale alpha
new float[] {adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1}};

imageAttributes = new ImageAttributes();
imageAttributes.ClearColorMatrix();
imageAttributes.SetColorMatrix(new ColorMatrix(ptsArray), ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
imageAttributes.SetGamma(gamma, ColorAdjustType.Bitmap);
Graphics g = Graphics.FromImage(adjustedImage);
g.DrawImage(originalImage, new Rectangle(0,0,adjustedImage.Width,adjustedImage.Height)
,0,0,bitImage.Width,bitImage.Height,
GraphicsUnit.Pixel, imageAttributes);

取得瀏覽器事件上的物件 IE/FF 相容式


// 取得瀏覽器事件上的物件 IE/FF 相容式

function abc(e) {
   var o=(document.all)?window.event.srcElement:e.target; 
}


[轉載] 一維條碼

轉載自 青衫(邱奕南)

一維條碼可分為39碼、EAN-13碼、EAN-8碼、UPC-A碼、UPC-E碼、交錯式25碼、CODABAR碼(又稱NW-7碼)、128碼等多種,以下便說明一下各種條碼的意義,以及編碼方式:

(一)39碼

39碼發展於1974年,由於限制少,又支援文數字,因此多應用於一般管理軟體。其編碼特性如下:

1. 資料碼可以是0~9、A~Z、-、.、Space、$、/、+、%等43種,資料長度不限,各資料編號次序依上列次序編號0~42。
2. 編碼結構為〔起始碼+資料碼+檢查碼+終止碼〕,其中檢查碼可有可無,且檢查碼亦會被視為資料輸入。
3. 起始碼與終止碼均固定為*。
4. 檢查碼為資料編號值(0~42)累加後(Sum)除以43取餘數,並將該值視為相對應資料編號值的資料。
5. 編碼資料如下,每碼有9條,其中3條為粗,各佔12線。以下各位元奇數位為黑,要畫線,偶數位為白,不畫線,0為細,1為粗:

0 000110100
1 100100001
2 001100001
3 101100000
4 000110001
5 100110000
6 001110000
7 000100101
8 100100100
9 001100100
A 100001001
B 001001001
C 101001000
D 000011001
E 100011000
F 001011000
G 000001101
H 100001100
I 001001100
J 000011100
K 100000011
L 001000011
M 101000010
N 000010011
O 100010010
P 001010010
Q 000000111
R 100000110
S 001000110
T 000010110
U 110000001
V 011000001
W 111000000
X 010010001
Y 110010000
Z 011010000
- 010000101
. 110000100
Space 011000100
$ 010101000
/ 010100010
+ 010001010
% 000101010
* 010010100

各資料碼之間必須再空開一條白線。


(二)EAN-13碼

EAN-13碼(European Article Number,歐洲商品條碼)是1977年由歐洲十二個工業國家所共同發展出來的一種條碼系統,其後逐漸變成國際性的條碼系統,一般多用作商品標示條碼。其編碼特性如下:

1. 資料只能為0~9之數字計12個,連同檢查碼共13碼。資料中包括國家代碼3碼、廠商代碼4碼、產品代碼5碼,為一種專用於商品標示的條碼。
2. 編碼結構為〔護線+6個左資料碼+中線+5個右資料碼+檢查碼+護線〕,共佔119條線。其中在畫線時,護線和中線在下方均略長於資料碼,以便肉眼能明顯區分,但對於條碼機閱讀時並無差異。
3. 左資料的編碼方式有A、B兩組之分,而資料的第一碼隱藏在左資料碼的編碼方式,故實際只編出12碼。以下為左資料依首碼所對應使用的編碼方式:

0 AAAAAA
1 AABABB
2 AABBAB
3 AABBBA
4 ABAABB
5 ABBAAB
6 ABBBAA
7 ABABAB
8 ABABBA
9 ABBABA

4. 左資料的編碼方式,A組編碼為:

0 0001101
1 0011001
2 0010011
3 0111101
4 0100011
5 0110001
6 0101111
7 0111011
8 0110111
9 0001011

B組編碼為:

0 0100111
1 0110011
2 0011011
3 0100001
4 0011101
5 0111001
6 0000101
7 0010001
8 0001001
9 0010111

以上各位元0為白,1為黑。

5. 護線固定為101,中線固定為01010,各位元0為白,1為黑。
6. 右資料編碼方式固定為:

0 1110010
1 1100110
2 1101100
3 1000010
4 1011100
5 1001110
6 1010000
7 1000100
8 1001000
9 1110100

各位元0為白,1為黑。

7. 檢查碼計算方式為1000減去前12碼之奇數碼和與偶數碼和*3後,除以10取餘數。假設各碼依次為ABCDEFGHIJKLM,則M = (1000 - (A+C+E+G+I+K) - (B+D+F+H+J+L)*3) % 10。

(三)EAN-8碼

EAN-8碼為EAN-13碼的簡化型,除了少掉了廠商代碼外,其餘大致和EAN-13碼相同,其編碼特性如下:

1. 資料只能為0~9之數字計7個,連同檢查碼共8碼。資料中包括國家代碼3碼、產品代碼5碼。
2. 編碼結構為〔護線+4個左資料碼+中線+3個資料碼+檢查碼+護線〕,共佔67條線。其中在畫線時,護線和中線在下方均略長於資料碼,以便肉眼能明顯區分,但對於條碼機閱讀時並無差異。
3. 首碼不再隱藏於編碼方式,因此實際編出8碼。左資料一律以A組方式編碼,右資料編碼方式同EAN-13碼(請參閱EAN-13碼)。
4. 檢查碼為1000減去前7碼之奇數碼和*3與偶數碼和後,除以10取餘數。假設各碼依次為ABCDEFGH,則
H = (1000 - (A+C+E+G)*3 - (B+D+F)) % 10。



(四)UPC-A碼

UPC-A碼(Universal Product Code,統一商品條碼)為1973年由美國超級市場公會所發展出來的條碼系統,適用於加拿大以及北美等地區,亦為EAN碼的前身,因此和EAN碼極為相似。UPC-A碼共有13碼,除了最後一個檢查碼外,還包括了旗碼2碼、廠商代碼5碼、產品代碼5碼。其中旗碼第一碼固定為0,第二碼用以表示商品的種類。整個UPC-A的編碼結構和EAN-13碼是完全相同的,只是首碼必須固定為0,因此在編碼上較EAN-13碼簡單。

(五)UPC-E碼

UPC-E碼為UPC-A碼的簡化型,共計有8碼,係由某些特殊的UPC-A碼簡化而來。由於並非所有UPC-A碼均能簡化成UPC-E碼,因此可簡化的UPC-A碼有一定的限制,這些限制為:

1. 旗碼=00,廠商代碼=xx000,產品代碼=00xxx
2. 旗碼=00,廠商代碼=xx100,產品代碼=00xxx
3. 旗碼=00,廠商代碼=xx200,產品代碼=00xxx
4. 旗碼=00,廠商代碼=xxx00,產品代碼=000xx
5. 旗碼=00,廠商代碼=xxxx0,產品代碼=0000x
6. 旗碼=00,廠商代碼=xxxxx,產品代碼=00005~00009

假設UPC-A各碼依次為ABCDEFGHIJKLM,則符合上述這些限制的UPC-A碼,可依次簡化成下列對應的UPC-E碼:

1. 0CDJKL0M
2. 0CDJKL1M
3. 0CDJKL2M
4. 0CDEKL3M
5. 0CDEFL4M
6. 0CDEFGLM

以下則為UPC-E碼的編碼特性:

1. 資料只能為0~9之數字計7個,連同檢查碼共8碼。各資料代表意義如前所述。
2. 編碼方式為〔左護線+6個資料碼+右護線〕,共佔51條線。由於第一碼固定為0,不列入編碼,而檢查碼隱含在編碼方式中,因此實際只編出6碼。
3. 資料碼依檢查碼有A、B兩組不同的編碼方式,各檢查碼對應的資料編碼方式如下:

0 BBBAAA
1 BBABAA
2 BBAABA
3 BBAAAB
4 BABBAA
5 BAABBA
6 BAAABB
7 BABABA
8 BABAAB
9 BAABAB

A、B兩組編碼方式同EAN-13碼。

4. 檢查碼計算方式如下:

0ABCDEFM : M = (1000 - (A+D+F) - (B+C+E)*3) % 10,F = 0~2
0ABCDE3M : M = (1000 - (A+C+D) - (B+E)*3) % 10
0ABCDE4M : M = (1000 - (A+C) - (B+D+E)*3) % 10
0ABCDEFM : M = (1000 - (A+C+E) - (B+D+F)*3) % 10,F = 5~9

5. 左護線固定為101,右護線固定為010101,以上各位元0為白,1為黑。



(六)交錯式25碼

交錯式25碼(Interleaved 2 of 5)發展於1972年,為最早出現的條碼系統。由於編碼方式係採2個資料交錯放置,且每個資料有5條線,故命令為交錯式25碼。其編碼特性如下:

1. 資料只能為0~9之數字,長度不限,但必須是偶數個,不足時最前面必須多補一個0。
2. 編碼結構為〔起始碼+資料碼+終止碼〕。
3. 編碼資料如下,每碼有5條線,其中2條為粗,故每碼各佔7線,各位元值0為細,1為粗:

0 00110
1 10001
2 01001
3 11000
4 00101
5 10100
6 01100
7 00011
8 10010
9 01010

實際編碼時,以2個資料之位元交錯放置,也就是第一個資料放一個位元,然後輪第二個資料放一個位元,再輪回第一個資料放一位元,如此循環下去。編碼完畢後,在奇數位者一律為黑(要畫線),偶數位者一律為白(不畫線)。

4. 起始碼固定為0000,終止碼固定為100。依前述奇數位為黑、偶數位為白、0為細、1為粗,則起始碼為細黑、細白、細黑、細白,而終止碼為粗黑、細白、細黑。

除了交錯式25碼外,也有沒進行交錯排列處理的標準式25碼(Standard 2 of 5),但使用上沒有交錯式25碼普及。

(七)CODABAR碼(又稱NW-7碼)

CODABAR碼發展於1972年,但直到1977年才正式被使用。由於發展年份和交錯式25碼相近,因此編碼方式有許多地方頗相似。其編碼特性如下:

1. 資料只能為數字0~9,以及/+-*$.:等7個特殊符號,長度最長為32碼資料。
2. 編碼結構為〔起始碼+資料碼+終止碼〕,其中起始碼和終止碼必須為英文字母A~D。
3. 編碼資料如下,每碼有7條線,長度不一,各位元奇數位為黑,偶數位為白,0為細,1為粗:

0 0000011
1 0000110
2 0001001
3 1100000
4 0010010
5 1000010
6 0100001
7 0100100
8 0110000
9 1001000
$ 0011000
- 0001100
A 0011010
B 0101001
C 0001011
D 0001110
+ 0010101
. 1010100
: 1000101
/ 1010001
* 1010101

各資料碼之間必須再空開一條白線。



(八)128碼

128碼是個功能強大卻頗複雜的條碼系統,約於1981年開始被採用。其編碼特性如下:

1. 資料可為ASCII 0~127之任何字元,長度最長30個資料。
2. 編碼結構為〔起始碼+資料碼+終止碼+檢查碼〕,其中檢查碼可有可無,通常不加。
3. 有三類編碼方式:

A類:ASCII 0~95。
B類:ASCII 32~127。
C類:數字00~99。

其中ASCII 0~31對應編碼索引為64~95,ASCII 32~95對應編碼索引為0~63,ASCII 96~127對應編碼索引為64~95,C類數字直接對應至編碼索引。各類尚有特殊編碼索引值如下:

A類:F3=96、F2=97、Shift=98、Code C=99、Code B=100、F4=101、F1=102
B類:F3=96、F2=97、Shift=98、Code C=99、F4=100、Code A=101、F1=102
C類:Code B=100、Code A=101、F1=102

4. 起始碼有11線,用以決定一開始的編碼類型,各類型的起始碼為:

A類 = 11010000100
B類 = 11010010000
C類 = 11010011100

終止碼有13線,固定為1100011101011。

5. 各編碼索引對應之編碼值如下,0表白線,1表黑線,各佔11條線:

00 11011001100
01 11001101100
02 11001100110
03 10010011000
04 10010001100
05 10001001100
06 10011001000
07 10011000100
08 10001100100
09 11001001000
10 11001000100
11 11000100100
12 10110011100
13 10011011100
14 10011001110
15 10111001100
16 10011101100
17 10011100110
18 11001110010
19 11001011100
20 11001001110
21 11011100100
22 11001110100
23 11101101110
24 11101001100
25 11100101100
26 11100100110
27 11101100100
28 11100110100
29 11100110010
30 11011011000
31 11011000110
32 11000110110
33 10100011000
34 10001011000
35 10001000110
36 10110001000
37 10001101000
38 10001100010
39 11010001000
40 11000101000
41 11000100010
42 10110111000
43 10110001110
44 10001101110
45 10111011000
46 10111000110
47 10001110110
48 11101110110
49 11010001110
50 11000101110
51 11011101000
52 11011100010
53 11011101110
54 11101011000
55 11101000110
56 11100010110
57 11101101000
58 11101100010
59 11100011010
60 11101111010
61 11001000010
62 11110001010
63 10100110000
64 10100001100
65 10010110000
66 10010000110
67 10000101100
68 10000100110
69 10110010000
70 10110000100
71 10011010000
72 10011000010
73 10000110100
74 10000110010
75 11000010010
76 11001010000
77 11110111010
78 11000010100
79 10001111010
80 10100111100
81 10010111100
82 10010011110
83 10111100100
84 10011110100
85 10011110010
86 11110100100
87 11110010100
88 11110010010
89 11011011110
90 11011110110
91 11110110110
92 10101111000
93 10100011110
94 10001011110
95 10111101000
96 10111100010
97 11110101000
98 11110100010
99 10111011110
100 10111011110
101 11101011110
102 11110101110



6. 檢查碼的計算方式103加上各資料的編碼索引值乘上位置值的總和,再除以103取餘數。假設資料編碼索引值依次為ABC,則檢查碼 = (103 + A*1 + B*2 + C*3) % 103。計算出檢查碼後,即視為編碼索引值進行編碼。
7. 特殊資料碼意義為:

F1~F4 = 同按下F1~F4鍵
Shift = 同按下Shift鍵
Code A = 編碼類別改成A類
Code B = 編碼類別改成B類
Code C = 編碼類別改成C類

由於128碼可以中途轉變編碼類別,因此同一個資料可能有多個編碼方式,如何將編碼長度縮到最小,便成為一項考驗。以下係我們經過分析後,所得到的演算法,可使得編碼長度縮到最小:

*** 決定起始碼

1. 一開始數字連續4個以上時,使用C類。
2. 先遇上ASCII 0~31者,使用A類,先遇上ASCII 96~127者,使用B類。都遇不上,一律採用A類。

*** 中途轉碼考慮

A、B類 -

1. 數字6個以上時,改用C類。
2. 遇上ASCII 0~31者,改用A類,遇上ASCII 96~127,改用B類。

C類 -

3. 只剩0~1個數字時,往後找2的情況,若無,一律使用A類。
4. 遇上ASCII 0~31者,改用A類,遇上ASCII 96~127,改用B類。

在ASP將字串轉成 Big5 位元串以十六進制表示

古老的 ASP 程式通常都在 ANSI 模式下。

近年來已朝向 Unicode (UTF-8) 的環境開發
在第一行加入: <%@LANGUAGE="VBScript" CODEPAGE="65001" %>
可以讓程式碼、語言核心、HTTP IO 都使用 Unicode 了。

如果有一個特殊狀況要把 Unicode 網頁的文字轉回去 Big5 怎麼辦呢?


'=== 將(Unicode)字串轉成 Big5 位元串以十六進制表示
Private Function HexBig5(strData)
Dim o,B,I,out
Set o = Server.CreateObject("ADODB.Stream")

o.Charset = "big5"
o.Mode = 3 '1讀 2寫 3讀寫
o.Type = 2 '1二進制 2純文字
o.Open
o.WriteText strData

'o.SaveToFile Server.MapPath("t.txt"),2 '測試輸出文字檔
o.Position = 0 '從頭開始
o.Charset = "big5"
o.Type = 1
B = o.Read

out = ""
For I= 1 To o.size
out = out & HexB(AscB(MidB(B,I,1)))
Next
HexBig5 = out
End Function

Private Function HexB(value)
hexB = Right("0" & HEX(value),2)
End Function

溢出字元

上篇討論到使用 Windows 內部的轉碼、轉字功能,事事不是那麼如意。Big5 碼並不是什麼字都有,Windows API 的轉碼功能遇到不能轉的字會變成「?」字元。
例如:

print ToANSI("陶喆的歌");

輸出 big5碼結果是:

陶?的歌

於是 Sean 再寫一個函式 ToHTML,輸出結果為:

陶&#21894;的歌

完整的原始程式在 這裡

在 Windows Perl 5.8 下的簡繁轉字

上篇文章使用 Windows 系統的 API 在 Unicode 與 ANSI 字元轉換。接下來就是簡體與繁的互換了。

雖然在 Perl 中可以 use Encode::HanConvert 來轉換。但還是同樣的問題,若要打包成執行檔會包出一大包怪物。在速度效能上的考量,Sean 還是使用 Windows API 來轉換。

在 GBK 字集中包含所有簡體與繁體字,所以 Sean 的程式都先轉成 GBK 再呼叫系統的 LCMapString。

這個函不該稱「簡繁轉碼」,應該稱「簡繁轉『字』」。因為編碼並沒有改變。函式傳入的字串使用 Unicode (Perl預設UTF8),回傳值也是 Unicode 字串,僅做簡繁字互轉。

Sean 已寫成 Perl 模組,完整的程式在這裡

題外話,簡繁體字並非一對一的關係唷,因為無法100%逆轉。
例如繁體「干」「幹」「乾」簡體皆為「干」,再轉回繁體還是「干」。






use Encode qw(encode decode);
use Win32::API;

use utf8;
use strict;

use constant LOCALE_SYSTEM_DEFAULT => 0x0800;
use constant LANG_CHINESE_SIMPLIFIED => 0x0804;
use constant LANG_CHINESE_TRADITIONAL => 0x0404;
use constant LCMAP_SIMPLIFIED_CHINESE => 0x02000000;
use constant LCMAP_TRADITIONAL_CHINESE => 0x04000000;

# Perl 的 Unicode 字串正體中文轉簡體中文
sub ToCHS {
my $source = ToANSI(shift,'GBK');
my $len = length($source);
my $target = "\0" x $len;

$API_LCMapString = new Win32::API('kernel32','LCMapString','NNPNPN','N') unless defined $API_LCMapString;

my $ret = $API_LCMapString->Call(LANG_CHINESE_SIMPLIFIED,LCMAP_SIMPLIFIED_CHINESE,$source,$len,$target,$len);
return undef unless $ret;

return(ToUnicode($target,'GBK'));
}


# Perl 的 Unicode 字串簡體中文轉正體中文
sub ToCHT {
my $source = ToANSI(shift,'GBK');
my $len = length($source);
my $target = "\0" x $len;

$API_LCMapString = new Win32::API('kernel32','LCMapString','NNPNPN','N') unless defined $API_LCMapString;

my $ret = $API_LCMapString->Call(LANG_CHINESE_SIMPLIFIED,LCMAP_TRADITIONAL_CHINESE,$source,$len,$target,$len);
return undef unless $ret;

return(ToUnicode($target,'GBK'));
}



在 Windows Perl 5.8 中 Unicode / ANSI 互轉

在 Perl 5.8 中使用字元集轉碼功能通常 use Encode。若在 Windows 下使用 PerlApp 之類的工具,將程式包成獨立的執行檔,通常會包出很龐大的執行檔。因為裡面包含著不小的轉碼表。

例如 encode 用到 big5 至少要 use Encode::TW,這麼一來檔案至少膨脹了好幾百K。而且你還無法預期不只有 TW 或許 CN, JP.... 都有可能用到。

Sean 寫了一個模組呼叫 Windows API 來轉碼,不使用 Perl 裡面的。
當然只能在 Windows 上跑,但可以將 Perl 程式包出較小的執行檔。

使用時請注意,如果程式碼中有 "中文字串",您的原始碼文字檔必須是 UTF8 格式。




package Win32Encode;

use Encode qw(encode decode);
use Win32::API;

use utf8;
use strict;

use Exporter;

use vars qw(
$VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS
%cp $API_MultiByteToWideChar $API_WideCharToMultiByte
);

$VERSION = '0.01';
@ISA = qw(Exporter);
@EXPORT = qw( ToUnicode ToANSI );
@EXPORT_OK = qw( ToUnicode ToANSI );


%cp = qw( EBCDICCPUS 37 437 437 CP437 437 CSPC8 437 CODEPAGE437 437 IBM437 437
ASMO708 708 DOS720 720 IBM737 737 CP500 775 IBM775 775 IBM850 850 IBM852 852
CP852 852 IBM857 857 IBM861 861 DOS862 862 CP866 866 IBM866 866 IBM869 869
CP870 870 ISO885911 874 DOS874 874 WINDOWS874 874 TIS620 874
XEBCDICGREEKMODERN 875 MSKANJI 932 CSSHIFTJIS 932 CSWINDOWS31J 932
XMSCP932 932 SHIFTJIS 932 XSJIS 932 CSISO58GB231280 936 GBK 936
GB231280 936 CSGB2312 936 CHINESE 936 CNGB 936 ISOIR58 936 GB2312 936
CSGB231280 936 KSC5601 949 KOREAN 949 KSC56011989 949 CSKSC56011987 949
KSC56011987 949 ISOIR149 949 CSBIG5 950 BIG5 950 XXBIG5 950 CNBIG5 950
CP1026 1026 XEBCDICCPUSEURO 1140 XEBCDICGERMANYEURO 1141
XEBCDICDENMARKNORWAYEURO 1142 XEBCDICFINLANDSWEDENEURO 1143
XEBCDICFRANCE 1143 XEBCDICITALYEURO 1144 XEBCDICSPAINEURO 1145
XEBCDICUKEURO 1146 XEBCDICFRANCEEURO 1147 XEBCDICINTERNATIONALEURO 1148
XEBCDICICELANDICEURO 1149 UNICODE 1200 UTF16 1200 UNICODEFFFE 1201
WINDOWS1250 1250 XCP1250 1250 WINDOWS1251 1251 XCP1251 1251 ISO646US 1252
WINDOWS1252 1252 ISO646IRV1991 1252 USASCII 1252 IBM819 1252 LATIN1 1252
CP819 1252 XANSI 1252 ANSIX341986 1252 ISOIR6 1252 ISO885911987 1252 ASCII 1252
ISOIR100 1252 US 1252 ANSIX341968 1252 CSASCII 1252 CP367 1252 ISO88591 1252
IBM367 1252 WINDOWS1253 1253 WINDOWS1254 1254 ISOIR148 1254 ISO88599 1254
LATIN5 1254 ISO885991989 1254 ISO88598I 1255 VISUAL 1255 WINDOWS1255 1255
ISO88598 1255 WINDOWS1256 1256 CP1256 1256 WINDOWS1257 1257 WINDOWS1258 1258
JOHAB 1361 MACINTOSH 10000 XMACJAPANESE 10001 XMACCHINESETRAD 10002
XMACKOREAN 10003 XMACARABIC 10004 XMACHEBREW 10005 XMACGREEK 10006
XMACCYRILLIC 10007 XMACCHINESESIMP 10008 XMACCE 10029 XMACICELANDIC 10079
XMACTURKISH 10081 XCHINESECNS 20000 XCHINESEETEN 20002 XIA5 20105
XIA5GERMAN 20106 XIA5SWEDISH 20107 XIA5NORWEGIAN 20108 ISOIR6US 20127
XEBCDICGERMANY 20273 XEBCDICDENMARKNORWAY 20277 XEBCDICFINLANDSWEDEN 20278
XEBCDICITALY 20280 XEBCDICSPAIN 20284 XEBCDICUK 20285
XEBCDICJAPANESEKATAKANA 20290 XEBCDICARABIC 20420 XEBCDICGREEK 20423
XEBCDICHEBREW 20424 XEBCDICKOREANEXTENDED 20833 XEBCDICTHAI 20838
CSKOI8R 20866 KOI 20866 KOI8 20866 KOI8R 20866 XEBCDICICELANDIC 20871
XEBCDICCYRILLICRUSSIAN 20880 XEBCDICTURKISH 20905
XEBCDICCYRILLICSERBIANBULGARIAN 21025 KOI8U 21866 KOI8RU 21866 L1 28591
CSISO 28591 L2 28592 ISOIR101 28592 ISO88592 28592 CSISOLATIN2 28592
LATIN2 28592 ISO885921987 28592 ISO88593 28593 ISO885931988 28593
ISOIR109 28593 LATIN3 28593 L3 28593 LATIN4 28594 ISO885941988 28594
ISOIR110 28594 L4 28594 ISO88594 28594 CSISOLATIN4 28594 ISO88595 28595
CYRILLIC 28595 ISOIR144 28595 CSISOLATIN5 28595 CSISOLATINCYRILLIC 28595
ISO885951988 28595 ECMA114 28596 ISO885961987 28596 ARABIC 28596 ISOIR127 28596
ISO88596 28596 CSISOLATINARABIC 28596 GREEK8 28597 ELOT928 28597
ISO885971987 28597 CSISOLATINGREEK 28597 ISO88597 28597 ECMA118 28597
ISOIR126 28597 GREEK 28597 HEBREW 28598 ISO885981988 28598
CSISOLATINHEBREW 28598 ISOIR138 28598 L5 28599 L9 28605 LATIN9 28605
ISO885915 28605 XEUROPA 29001 LOGICAL 38598 ISO2022JP 50221
CSISO2022JP 50221 CSISO2022KR 50225 ISO2022KR 50225
XEBCDICJAPANESEANDKANA 50930 XEBCDICJAPANESEANDUSCANADA 50931
XEBCDICKOREANANDKOREANEXTENDED 50933 XEBCDICSIMPLIFIEDCHINESE 50935
XEBCDICTRADITIONALCHINESE 50937 XEBCDICJAPANESEANDJAPANESELATIN 50939
XEUC 51932 EUCJP 51932 XEUCJP 51932
EXTENDEDUNIXCODEPACKEDFORMATFORJAPANESE 51932 CSEUCPKDFMTJAPANESE 51932
EUCCN 51936 XEUCCN 51936 EUCKR 51949 CSEUCKR 51949 HZGB2312 52936
XISCIIDE 57002 XISCIIBE 57003 XISCIITA 57004 XISCIITE 57005 XISCIIAS 57006
XISCIIOR 57007 XISCIIKA 57008 XISCIIMA 57009 XISCIIGU 57010 XISCIIPA 57011
CSUNICODE11UTF7 65000 XUNICODE20UTF7 65000 UNICODE11UTF7 65000 UTF7 65000
XUNICODE20UTF8 65001 UTF8 65001 UNICODE20UTF8 65001 UNICODE11UTF8 65001);


# 使用 Windows API 互轉 ANSI 字元及 Perl Unicode 字串
#
#
# 原始碼以 utf-8 儲存時
# $ansi = ToANSI("中文字ABC\n"); # 相當於 encode("Big5","中文ABC") 傳回的 Big5 byte 型式
# $unicode = ToUnicode($ansi); # 轉成 Perl Unicode 字串
#
# 字元集參數預設為 CP_ACP(0) 即系統預設語言


# 轉成多位元字元 (Perl 的 Unicode字串,[字元集])
sub ToANSI {

my($u8,$codepage) = @_;
$codepage ||=0;

unless($codepage =~ /^\d+$/) {
$codepage = uc($codepage);
$codepage =~ s/[^A-Z0-9]//g;
$codepage = (exists $cp{$codepage})?$cp{$codepage}:0;
}

my $u_len = length($u8);
my $uni_str = encode("UCS-2LE",$u8);

$API_WideCharToMultiByte = new Win32::API('kernel32','WideCharToMultiByte','NNPNPNPP','N') unless defined $API_WideCharToMultiByte;

my $len = $API_WideCharToMultiByte->Call($codepage,0,$uni_str,$u_len,0,0,0,0);
return undef unless $len;

my $string = "\0" x $len;

my $result = $API_WideCharToMultiByte->Call($codepage,0,$uni_str,$u_len,$string,$len,0,0);
return undef unless $result;

return($string);
}



# 轉成 Perl 的 Unicode 字串( ANSI字串,[字元集] )
sub ToUnicode {

my($string,$codepage) = @_;
$codepage ||=0;

unless($codepage =~ /^\d+$/) {
$codepage = uc($codepage);
$codepage =~ s/[^A-Z0-9]//g;
$codepage = (exists $cp{$codepage})?$cp{$codepage}:0;
}

$API_MultiByteToWideChar = new Win32::API('kernel32','MultiByteToWideChar','NNPNPN','N') unless defined $API_MultiByteToWideChar;

my $len = $API_MultiByteToWideChar->Call($codepage,0,$string,length($string),0,0);
return undef unless $len;

my $ustring = "\0" x ($len*2);

my $result = $API_MultiByteToWideChar->Call($codepage,0,$string,length($string),$ustring,$len);
return undef unless $result;

return decode("UCS-2LE",$ustring);
}

1;







題外話。為了更減輕打包出來的大小,C:\Perl\lib\unicore 目錄可以只剩下列檔案:

Canonical.pl
Exact.pl
PVA.pl
lib\gc_sc\Digit.pl
lib\gc_sc\SpacePer.pl
lib\gc_sc\Word.pl
To\Digit.pl
To\Fold.pl
To\Lower.pl
To\Title.pl
To\Upper.pl

這只是通常的情況,保險一點修改 C:\Perl\lib\utf8_heavy.pl 裡的 DEBUG 為 1。
把自己的程式跑一遍,看看有沒有缺少哪個 unicore 裡的檔案。

讓 Blogger 的意見回應可以有回覆

新方法改起來比較容易囉,見 新文章(2010/12/23)。下面是舊方法,忘記它吧。


Blogger 中的張點的意見(回應)都沒有「作者回覆」的功能,剛剛 hack 一下... 終於有了。
曾看過其他解決方案,但要申請第三方留言版來外掛。
我的方法不用另外申請,直使用 Blogger 資料庫。



版面配置 → 修改 HTML → 勾「展開小裝置範本」
「下載完整範本」後,用習慣的編輯器來改。

修改後再上傳。最好是能把最原始範本保留一份起來,免得改錯了來找我。
注意,每個人的 Template 或許不同。紅色為新增部份。
<script type='text/javascript'>
function authorReply(CID) {
var strBody = document.getElementById(CID).innerHTML.replace(/Re:\s*.+\s*&amp;lt;(\d+)&amp;gt;\s*&lt;BR\/?&gt;/i,&#39;&#39;);
var strOut = &quot;<div style='background-color: bisque; padding: 4px'><b>作者回覆</b>&#65306;<br/>&quot;+strBody+&#39;</div><p/>&#39;;
if(RegExp.$1)
document.getElementById(&#39;RID&#39;+RegExp.$1).innerHTML = strOut;
else
document.write(strOut);
}

function replyEmbedComment(CN,CID) {
var url = document.getElementById(&#39;comment-editor-src&#39;).href.replace(/-iframe/,'');
url += &quot;&amp;postBody=Re:+&quot;+escape(CN)+&quot;+&lt;&quot;+CID+&quot;&gt;%0D%0A&quot;;
location.href = url;
}
</script>

<dl id='comments-block'>
<b:loop values='data:post.comments' var='comment'>

 <b:if cond='data:comment.author == data:post.author'>
 <div expr:id='&quot;CID&quot; + data:comment.id' style='display:none'><data:comment.body/> <span style='font: 7pt Arial; color:#8a8a8a'>(<data:comment.timestamp/>)</span>
<b:include data='comment' name='commentDeleteIcon'/>
</div>
<script type='text/javascript'>
authorReply(&quot;CID<data:comment.id/>&quot;);
</script>
<b:else/>
  <dt expr:class='&quot;comment-author &quot; + data:comment.authorClass' expr:id='data:comment.anchorName'>
<a expr:name='data:comment.anchorName'/>
<b:if cond='data:comment.authorUrl'>
<a expr:href='data:comment.authorUrl' rel='nofollow'><data:comment.author/></a>
<b:else/>
<data:comment.author/>
</b:if>
<data:commentPostedByMsg/>
</dt>
<dd class='comment-body'>
<b:if cond='data:comment.isDeleted'>
<span class='deleted-comment'><data:comment.body/></span>
<b:else/>
<p><data:comment.body/></p>
</b:if>
</dd>
<dd class='comment-footer'>
<span class='comment-timestamp'>
<a expr:href='data:comment.url' title='comment permalink'>
<data:comment.timestamp/>
</a>
<b:include data='comment' name='commentDeleteIcon'/>







<span expr:class='&quot;item-control &quot; + data:comment.adminClass'>
<b:if cond='data:post.embedCommentForm'>
<a href='#comment-form' expr:onclick='&quot;replyEmbedComment(\&quot;&quot; + data:comment.author + &quot;\&quot;,\&quot;&quot; + data:comment.id + &quot;\&quot;)&quot;' style='font: 9pt Arial; color:#8a8a8a'>回</a>
<b:else/>
<b:if cond='data:post.allowComments'>
<a expr:href='data:post.addCommentUrl + &quot;&amp;postBody=Re%3A%20&quot; + data:comment.author + &quot;%20%3C&quot; + data:comment.id + &quot;%3E%0D%0A&quot;' expr:onclick='data:post.addCommentOnclick' style='font: 9pt Arial; color:#8a8a8a'>回</a>
</b:if>
</b:if>
</span>










</span>
</dd>
  <dd class='comment-reply'>
<span expr:id='&quot;RID&quot; + data:comment.id'/>
</dd>
</b:if>

</b:loop>
</dl>







完成之後....
在使用者登入的情況下在每篇「意見」後面都會多一個「回」字。用力點下去就對了!






寫回覆內容時,自動出現的第一行要留起來唷。不然就會變成普通留言。

單一網卡同時設定「自動取得IP」及固定的「靜態IP」

Use a DHCP obtained IP address along with a static IP address at the same time.



如果懶得找 Registry,請下載小弟寫的 Script 程式來輔助設定。


最近申請 Cable Modem 發現一個問題,雖然不用 PPPoE 撥接很方便。但是它提供的 DHCP 發給的 IP 都不在同網段,家裡區網的網芳互連很不方便。以下文章介紹如何在一片網卡上自定私有的靜態 IP,又同時「自動取得 IP 位址」(DHCP)。

XP 的 Internet Protocll (TCP/IP) 網路設定「使用下列的 IP 位址」再按 [進階] 可以設定多個靜態 IP。但是如果使用「自動取得 IP 位址(DHCP)」的話將無法在同一片網卡上設定其他 IP。想要在同一片網卡上有兩個 IP(一個是 DHCP 發下來的,另一個是自定的),使用 Regedit 修改註冊表即可。

  • 先將 TCP/IP 設成「自動取得 IP 位址」。


  • 執行 Regedit 找
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards\數字
    上面的「數字」可能好幾個,要找:

    Description = 你的網卡名稱
    ServiceName = {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} ← 長得像這樣。


  • 再找 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}]

    編輯 IPAddress 第二行加上你要增加的 IP 按 Enter 加換行。

    編輯 SubnetMask 第二行加上 255.255.255.0 (一般是這樣),按 Enter 加換行。


  • 「區域連線」上按右鍵「停用」再「啟用」,看看 ipconfig /all 是不多了一組IP。

!!注意!! 一台電腦同時具有 WAN + LAN 時要特別注意網路安全。

ID3批次編輯工具 - ID3 Batch Editing



Edit your MP3 information the way you like in Office Excel!
(Multilanguage support)

■ 最新版本:v2.2

■ 發佈日期:2008 年 8 月 28 日

■ 介面語言:英文、簡體中文、正體中文

■ 檔案下載:id3xls23a_install.exe (2.1 MB)



■ 功能說明:


編輯 ID3 資訊是一件麻煩的事。如果您習慣 Excel 的編輯環境,使用它來編輯 ID3、複製文字、剪剪貼貼。那是不是方便多了?不管你是從無到有、或是修改現有的 ID3 資訊,使用這個程式都可以方便的完成。

農曆月曆&世界時間 DHTML 程式

版本日期:2007年3月6日



■ 純 HTML 版本:


■ Sidebar Gadget 版本 (for Windows Vista/7):