2008年12月29日星期一

[遊戲介紹]卡坦島騎士擴充

http://heyjude0929.pixnet.net/blog/post/23649454

卡坦島野蠻人擴充Catan: Traders & Barbarians

http://heyjude0929.pixnet.net/blog/post/23409600

perl 代码片断

1:剔出c cpp h文件中的注释空行 by 20020220 太田君より入手
#############################################################################################
# 指定されたファイルのコメントと空行を取り去る
#--------------------------------------------------------------------------------------------
sub strip_comment {
my $in_file = shift;
my $out_file = shift;
open IN, $in_file or die("Canot open file");
open OUT, ">$out_file";

while ( ) {
chop;
my $in_comment = 0;
my $content = $_;

#
# 最初に /* ... */ , // .... が合成記述のチェックを行う
#
if ( $content =~ m/^(.*)\/\*(.*)\*\/(.*)$/) { # /* */を1行中に発見
if ($content =~ m/^\/\/.*$/) { # 先頭に//がある?
next; # 全部コメント行なので次の行へ(ループ)
}
elsif ($content =~ m/^(.*)\*\/\/\*(.*)$/ ) { # /* ... *//* .....のパターンは通常処理
;
}
elsif ($content =~ s/^(.*?)\/\/*\/\*(.*)$//) { # ... //* ... */...のパターン発見
$_ = $1; # ...// の前部分を通常処理の対象とする
$content = $1;
}
}

# 再度、通常の処理を実行する。

if ( s/^(.*)\/\*(.*)\*\/(.*)$/$1 $3/ ) { # /* */を同じ行に発見

while ( s/^(.*)\/\*(.*)\*\/(.*)$/$1 $3/ ) { # さらに/* */を同じ行でさがす
;
}
$content = $_;
}

if (m/^(.*)\/\*(.*)/) {
if (s/^(.*?)\/\/(.*)$/$1/) { $content =$1; $_ = $1}
}
if ( s/^(.*)\/\*(.*)$/$1/ ) { # 次に /* をさがす
$content = $_;
if ( ! /^[ \t]*$/ ) {
print OUT "$content\n";
}
while ( ) { # */を探して行を進める
chop;
$content = $_;
if ( s/^(.*)\*\/(.*)$/$2/ ) { # */を発見?
$content = $_;
last;
}
}
}
elsif ( s/^(.*?)\/\/.*$/$1/ ) { # V1.10 //を検索し最初の//以降すべて削除
$content = $1;
}

$_ = $content;

if ( /^[ \t]*\r$/ ) { # V1.6 spacespacespace LF
}
elsif ( /^[ \t]*$/ ) { # spacespacespace
}
else {
print OUT "$content\n";
}
}
close IN;
close OUT;
}

2008年12月22日星期一

卡坦島--C & K 扩展

Cities & Knights of Catan, The 卡坦島 - 城市及騎士

年份:1998
出版商:Mayfair Games, Kosmos, Tilsit
作者:Klaus Teuber
人數:3 - 4
年齡:10 +
時間:120 + 分鐘

這是「The Settlers of Catan 卡坦島 - 拓荒者」的附加配件。玩家必須先持有「The Settlers of Catan 卡坦島 - 拓荒者」遊戲,方可加入這配件。

加入這附加配件後,遊戲的佈局雖大同小異,但玩法即會有所改變。原先拓荒者中的發展卡development將會棄用,以城市發展取代,讓 玩家可換取科學、政治、商業3項進步卡progress。玩家各有其城市發展圖冊,圖冊上分為科學、政治、商業3段,可分別揭頁以代表玩家的進度。拓荒者 中的城鎮,可建造成重要的文化、宗教、貿易城市。

城市發展是以支付商品作代價。新加入的紙張、錢幣、布匹3種商品。玩家建有城市時,於森林、山脈、或草原上不再是生產2件木材、礦石或羊 毛,而是木材+紙張、礦石+錢幣或羊毛+布匹。紙張、錢幣及布匹,各用於提升科學、政治及商業發展。只有提升城市發展,玩家方可能取得進步卡。
由於沒有了發展卡,遊戲取消了「最大軍隊」的獎分,另加入了蠻族、騎士、城牆等原素。

每回合玩家由擲2顆骰,改為擲骰3顆。3顆骰中1顆是事件骰,其中有半數機會蠻族的船隻會朝卡坦島前進,另半數機會玩家可能取得進步卡。蠻 族抵達卡坦島時,即點算卡坦島城市數目、可動用的騎士力量。若卡坦島城市數目多於可動用的騎士力量,玩家中可動用的騎士力量最少者,其擁有之一座城市即被 毀變回聚落。

遊戲中玩家最多可擁有6名騎士。騎士力量分1、2、3共3類。玩家可使用其騎士驅趕賊匪、截斷他人的道路、驅逐他人的騎士,更重要是對抗蠻族入侵。騎士棋子分灰色及彩色兩面,玩家必須付出1稻麥方可讓騎士出動。可動用的騎士以彩色一面放置,完成任務後,即以灰色一面放置。

玩家付出2磚塊,即可在其城市建設城牆,以方形木塊放到城市下代表。玩家最多建設3個城牆,當然玩家亦需最少有3座城市。城牆的作用是當賊 匪出動時,玩家手上貨品上限加多2張卡。因此建有2座有城牆的城市,玩家只有當持有11(7+4)張卡以上,方會在賊匪出動時丟棄半數貨品。

加入這配件後,玩家的目標是搶先取得13分。最先取得13分或以上者勝出遊戲。

必須留意的是,不同出版商所出的「卡坦島 – 城市及騎士 The Cities & Knights of Catan 」,只配合其出版的「The Settlers of Catan 卡坦島 - 拓荒者」,否則圖板、棋子將會出現不吻合的情況。例如Mayfair出的英文版,必須配合其出版的附加配件。Kosmos出的德文版,亦只配合其出版的附加配件。

2008年11月24日星期一

各种食用油的使用注意

各种食用油的使用注意
hopexjlg 发表于 2007-7-26 18:29:00

生活中,许多人吃惯了一种口味的油,往往会长期食用。其实,不同种类的食用油各具特点,从营养平衡角度出发,选用时不妨经常轮换着吃。
  豆油 含丰富的多不饱和脂肪酸和维生素E、D,有降低心血管疾病、提高免疫力、对体弱消瘦者有增加体重的作用。豆油含的多不饱和脂肪酸较多,所以在各种油脂中最容易酸败变质,因此购买时一定要选出厂不久的,并尽可能趁“新鲜”吃掉。
  玉米油 玉米油极易消化,人体吸收率高达97%。玉米油中不饱和脂肪酸含量达80%以上,其中的亚油酸是人体自身不能合成的必需脂肪酸,还含有丰富的维生素E。从口味和烹调角度来说,玉米油色泽金黄透明,清香扑鼻,除可用于煎、煮、炸外,还可直用于凉拌。
  橄榄油 所含的单不饱和脂肪酸是所有食用油中最高的一类,它有良好的降低低密度胆固醇,提高高密度胆固醇的作用,所以有预防心脑血管疾病、减少胆囊炎、胆结石发生 的作用。橄榄油还含维生素A、D、E、K、胡萝卜素,对改善消化功能、增强钙在骨骼中沉着、延缓脑萎缩有一定的作用。
  花生油 含丰富的油酸、卵磷脂和维生素A、D、E、K及生物活性很强的天然多酚类物质,可降低血小板凝聚,降低总胆固醇和坏胆固醇水平,预防动脉硬化及心脑血管疾病。
  葵花子油 含丰富的必需脂肪酸,其中亚油酸、α-亚麻酸在体内可合成与脑营养有关的DHA,孕妇吃葵花子油有利于胎儿脑发育。含有维生素E、A等,有软化血管、降低 胆固醇、预防心脑血管疾病、延缓衰老、防止干眼症、夜盲症、皮肤干燥的作用。葵花子油也含有较高的多不饱和脂肪酸,所以有与豆油一样的注意事项。
  色拉油 是植物油中加工等级最高的食用油,已基本除尽了植物油中的一切杂质和蜡质,所以颜色最淡。色拉油适用于炒、炸、煎和凉拌,这是其他食用油所不及的。
  猪油 含较高的饱和脂肪酸,吃得太多容易引起高血脂、脂肪肝、动脉硬化、肥胖等。但猪油不可不吃,因为其所含胆固醇是人体制造类固醇激素、肾上腺皮质激素、性激素和自行合成维生素D的原料。猪油中的α-脂蛋白能延长寿命,这是植物油中所缺乏的。

2008年11月11日星期二

To read;

http://svn.perlchina.org/trunk/POD2-CN/lib/POD2/CN/perlvar.pod
NAME

perlvar - Perl 预定义变量



DESCRIPTION

预定义名称

后面列出的名称对 Perl 来说具有特殊含义。

大多数标点名称都有合理的助记方法或类似于在 shell 中的用法。

然而,如果你就是想用长变量名,那只要在程序开头加上



use English;



即可。这样会为所有短名称在当前包中创建长名称别名。

其中一些甚至还有中间名,一般是从 awk 借用过来的。 一般来说,如果不需要

$PREMATCH,$MATCH 和 $POSTMATCH,那最好使用



use English '-no_match_vars';



调用方式,因为它能避免在用正则表达式时出现效率降低的情况。见 English。



依赖当前被选中文件句柄的变量可以通过在 IO::Handle

对象上调用合适的对象方法来设置,

但是这要比使用普通的内建变量效率低一些。(下面的概括行里包含的单词 HANDLE

即指 IO::Handle 对象。) 首先你要声明



use IO::Handle;



然后就可以用



method HANDLE EXPR



或者更安全的形式,



HANDLE->method(EXPR)



每个方法都返回 IO::Handle 属性的旧值,同时接受一个可选的 EXPR。

如果提供了该参数,则其指定了所涉及 IO::Handle

属性的新值。如果不提供该参数, 大多数方法不改变当前值--除了

autoflush(),它会假定给定了参数 1,稍有不同。



载入 IO::Handle

类是一项代价高昂的操作,因此你该知道如何使用常规的内建变量。



这些变量中的少数几个是“只读的”。这意味着如果直接或者通过引用间接向该变

量赋值, 就会引起一个运行时异常。



在修改本文档中描述的大部分特殊变量的缺省值时都需要特别小心。多数情况下应



在修改之前局部化这些变量,如果不这么做,就可能影响依赖于你所修改特殊变量

缺 省值的其他模块。下面是一次性读入整个文件的一种正确方法:



open my $fh, "foo" or die $!;

local $/; # enable localized slurp mode

my $content = <$fh>;

close $fh;



但下面的代码就很糟糕:



open my $fh, "foo" or die $!;

undef $/; # enable slurp mode

my $content = <$fh>;

close $fh;



因为一些模块可能想以默认的“行模式”从文件中读取数据,而一旦我们刚才

列出的代码得到执行,在同一个 Perl 解释器内运行的所有其他代码读到的 $/

全局值都会被改变。



通常,在局部化一个变量时总是想让影响限制在尽可能小的范围内,因此

应该自己建立一个 "{}" 块,除非你已经处于某些小的 "{}" 块内。例如:



my $content = '';

open my $fh, "foo" or die $!;

{

local $/;

$content = <$fh>;

}

close $fh;



下面是代码失控的一个例子:



for (1..5){

nasty_break();

print "$_ ";

}

sub nasty_break {

$_ = 5;

# do something with $_

}



你可能希望上述代码打印出:



1 2 3 4 5



但实际上得到的却是:



5 5 5 5 5



为什么?因为 nasty_break() 修改了 $_ 而没有事先将其局部化。

改正方法是增加 local():



local $_ = 5;



虽然在这样一个短小的例子里很容易发现问题,但在更复杂的代码中,如果不

对特殊变量进行局部化更改就是在自找麻烦。



下列内容按照先标量变量、后数组、最后散列的顺序排列。



$ARG

$_ 默认的输入和模式搜索空间。下面的几对代码都是等同的:



while (<>) {...} # equivalent only in while!

while (defined($_ = <>)) {...}



/^Subject:/

$_ =~ /^Subject:/



tr/a-z/A-Z/

$_ =~ tr/a-z/A-Z/



chomp

chomp($_)



以下是几处即使没有写明 Perl 也会假定使用 $_ 的地方:



* 各种单目函数,包括像 ord() 和 int() 这样的函数以及除 "-t"

以外所有的文件 测试操作 ("-f","-d"),"-t" 默认操作 STDIN。



* 各种列表函数,例如 print() 和 unlink()。



* 没有使用 "=~" 运算符时的模式匹配操作 "m//"、"s///" 和

"tr///"。



* 在没有给出其他变量时是 "foreach" 循环的默认迭代变量。



* grep() 和 map() 函数的隐含迭代变量。



* 当 "while" 仅有唯一条件,且该条件是对 ""

操作的结果进行测试时,$_ 就是存放输入记录的默认位置。除了

"while" 测试条件之外不会发生这种情况。



(助记:下划线在特定操作中是可以省略的。)



$a

$b 是使用 sort() 时的特殊包变量,参见 "sort" in perlfunc。

由于这一特殊性,$a 和 $b 即使在用了 "strict 'vars'"

指示符以后也不需要声明(用 use vars 或者 our())。 如果想要在

sort() 的比较块或者函数中使用它们,就不要用 "my $a" 或 "my $b"

将其词法化。



$<*digits*>

含有上次模式匹配中捕获括号集合所对应的子模式,不包括已经退出的嵌

套 块中匹配的模式。(助记:类似 \digits。)

这些变量全都是只读的,对于 当前块来说具有动态作用域。



$MATCH

$& 含有上次成功的模式匹配所匹配到的字符串(不包括任何隐藏在块中的匹?

浠虻鼻?块所包围的 eval())。(助记:同一些编辑器中的 & 类似。)

该变量是只读的, 对于当前块来说具有动态作用域。



在程序中任何地方使用该变量都会使所有正则表达式匹配产生可观的效率

降低。 参见 "BUGS"。



$PREMATCH

$` 含有上次成功的模式匹配内容之前的字符串(不包括任何隐藏在块中的匹?

浠虻鼻?块所包围的 eval)。(助记:"`"

常常出现在引起的字符串之前。) 该变量是只读的。



在程序中任何地方使用该变量都会使所有正则表达式匹配产生可观的效率

降低。 参见 "BUGS"。



$POSTMATCH

$' 含有上次成功的模式匹配内容之后的字符串(不包括任何隐藏在块中的匹?

浠虻鼻?块所包围的 eval())。(助记:"'"

常常跟在引起的字符串之后。) 例如:



local $_ = 'abcdefghi';

/def/;

print "$`:$&:$'\n"; # prints abc:def:ghi



该变量只读且对于当前块具有动态作用域。



在程序中任何地方使用该变量都会使所有正则表达式匹配产生可观的效率

降低。 参见 "BUGS"。



$LAST_PAREN_MATCH

$+ 含有上次成功的搜索模式中最后一个括号匹配的文本。在无法知道可选模

式集中 到底哪一个匹配成功时,该变量是非常有用的。例如:



/Version: (.*)|Revision: (.*)/ && ($rev = $+);



(助记:积极一点儿向前看。)(译注:“积极”与“正号”是同一个单词?

? 该变量只读且相对于当前块具有动态作用域。



$^N 含有上一次成功搜索模式中最近闭合的组(即最右边的右括号构成的组)所

匹配 的文本。(助记:最近闭合的(可能)嵌套的括号。)

(译注:嵌套的单词为 Nest。)



该变量主要用在 "(?{...})"

块的内部,以便检查最近匹配到的文本。例如,

为了有效地用一个变量($1、$2 等等之外的变量)捕获文本,可以将

"(...)" 替换为



(?:(...)(?{ $var = $^N }))



像这样设置并使用 $var 就能把你从计算括号个数的烦恼中解放出来了。



该变量对于当前块具有动态作用域。



@LAST_MATCH_END

@+ 该数组保存了当前活动的动态作用域中最近成功的子匹配结束处的偏移量

。 $+[0]

为整个匹配在字符串中结束处的偏移量,这同用被匹配的变量调用 "pos"

函数得到的值一样。该数组的第 *n* 个元素保存了第 *n* 个子匹配

的偏移量,因此 $+[1] 就是紧接着 $1 结束处的偏移量,$+[2] 是

紧接着 $2 结束处的偏移量,以此类推。可以用 $#+

得知最近成功的匹配 中有多少个组。参见为 "@-" 变量给出的例子。



$* 将其设为非零整数值就可以进行字符串内的多行匹配,设为

0(或未定义值) 相当于告诉 Perl

可以假定字符串都是单行的,从而能进行模式匹配的优化。当 $* 为 0

或未定义值时,对含有多个换行符的字符串进行模式匹配会产生很难

理解的结果。它默认为未定义值。(助记:* 匹配很多东西。)

该变量只影响对 "^" 和 "$" 的解释。即使在 "$* == 0"

时也可以搜索一个字面的换行符。



在现在的 Perl 里不应使用 $*,在模式匹配中可以用 "/s" 和 "/m"

修饰符取代 它的功能。



对 $* 赋非数值量会触发一个警告(并使 $* 表现为 "$* == 0"),对 $*

赋数值量则会隐含对其应用 "int"。



HANDLE->input_line_number(EXPR)

$INPUT_LINE_NUMBER

$NR

$. 为最后访问的文件句柄对应的当前行号。



Perl 中每个文件句柄都记录从其中读出的行数。(Perl

中行的概念也许和你不一 样,要看 $/ 的值是什么。)

当从某个文件句柄中读出一行(通过 readline() 或 "<>")或对其调用

tell() 或 seek() 时,$. 即成为那个句柄的行 计数器的别名。



你可以通过向 $. 赋值来调整计数器,但这并不会实际移动文件指针。

*局部化 $. 不会使对应文件句柄的行计数器局部化*,而只会局部化 $.

和文件句柄的别名关系。



关闭文件句柄时会复位 $.,但在没有 close()

就重新打开一个已打开的文件句柄 时不会这样。更多细节参见 "I/O

Operators" in perlop。"<>" 从不显式关闭文件,因此行号会在 ARGV

文件之间持续增长(不过请看看 "eof" in perlfunc 中的例子)。



你还可以用 "HANDLE->input_line_number(EXPR)"

访问一个给定文件句柄的

行计数器,这样就无需担心最后访问的是哪个句柄了。



(助记:很多程序用“.”表示当前行号。)



IO::Handle->input_record_separator(EXPR)

$INPUT_RECORD_SEPARATOR

$RS

$/ 为输入记录分隔符,默认为换行符。该变量会影响 Perl

对“行”这一概念 的理解。其功能类似于 awk 中的 RS

变量,在被设置为空字符串时同样

会将空白行作为终止标志。(空白行不能含有任何空格或制表符。)

你可以将其

设置为含有多个字符的字符串,以匹配多字符的终止标志;也可以设为

"undef" 以便一直读到文件结束。当文件含有连续的空白行时,把它设为

"\n\n" 和设为 "" 有少许不同:设为 ""

会把两个或更多连续的空白行视为单个 空白行;而设为 "\n\n"

则只是盲目地假定其后输入的字符属于下一段,即使

这些字符是换行符也一样。(助记:在引用诗句时会用 /

作为行间的分隔。)



local $/; # enable "slurp" mode

local $_ = ; # whole file now here

s/\n[ \t]+/ /g;



切记:$/ 的内容是一个字符串,而不是正则表达式。awk

得在某些方面改进 一下了。:-)



将 $/

设为整数、存有整数的标量或可转换成整数的标量这些值的引用时,Perl

会尝试读入记录而不是行,最大记录长度就是引用的那个整数。因此这段

代码:



local $/ = \32768; # or \"32768", or \$var_containing_32768

open my $fh, $myfile or die $!;

local $_ = <$fh>;



会从 FILE 读取一条不长于 32768

字节的记录。如果你不是在读取一个面向记录 的文件(或者所用的 OS

没有面向记录的文件类型),那很可能每次读取都得到一

整块的数据。若某条记录比你所设置的记录长度还大,就会把该记录拆成

若干片 返回。



在 VMS 上,记录读取是用 "sysread"

的等价物完成的,因此最好不要在同一个

文件上混合使用记录和非记录读。(这不太可能成为问题,因为任何你想?

约锹寄J?读取的文件也许都不能在行模式下用。) 非 VMS 系统用普通

I/O 进行读取,因此 在一个文件中混合记录和非记录读是安全的。



参见 "Newlines" in perlport 以及 $.。



HANDLE->autoflush(EXPR)

$OUTPUT_AUTOFLUSH

$| 若将该变量设为非零值,就会立刻强制进行刷新,并且当前选中的输出通

道在每次 打印或写之后都会进行刷新。默认值为 0

(不管选中的通道实际上是否被系统所缓冲, $| 只是告诉你 Perl

是否在每次写完之后显式刷新)。典型情况下,若 STDOUT

的输出是终端则是行缓冲的,否则就是块缓冲。设置该变量在向管道或套

接字输出 时很有用,比如你正在 rsh 下运行一个 Perl

程序并且想在输出时马上就能看到

输出内容。该变量不影响输入缓冲。关于输入缓冲请参见 "getc" in

perlfunc。 (助记:when you want your pipes to be piping hot.)



IO::Handle->output_field_separator EXPR

$OUTPUT_FIELD_SEPARATOR

$OFS

$, 为 print 的输出域分隔符。通常 print

不经任何修饰就输出它的参数,要 得到更像 awk

的行为,可以将该变量设置成和 awk 的 OFS 变量一样

,以指定域之间打印什么。(助记:当 print

语句里有“,”时会打印的东西。)



IO::Handle->output_record_separator EXPR

$OUTPUT_RECORD_SEPARATOR

$ORS

$\ 为 print 的输出记录分隔符。通常 print

简单地原样输出它的参数,不增加

任何结尾的换行符或其他表征记录结束的字符串。要得到更像 awk

的行为, 可以将该变量设为同 awk 的 ORS 变量一样,以指定在 print

的结尾输出 什么。(助记:设置 $\ 而不是在 print

结尾加“\n”。另外,它长得和 $/ 很像,但却是你从 Perl

那里拿“回”的东西。) (译注:“回”原文为

单词“back”,还指代反斜杠“backslash”,起一语双关作用。)



$LIST_SEPARATOR

$" 该变量同 $,

类似,但应用于向双引号引起的字符串(或类似的内插字符串)

中内插数组和切片值的场合。默认为一个空格。(助记:我觉得显而易见?

?



$SUBSCRIPT_SEPARATOR

$SUBSEP

$; 为模拟多维数组时的下标分隔符。如果你这样引用一个散列元素



$foo{$a,$b,$c}



实际上意思就是



$foo{join($;, $a, $b, $c)}



但是别这么写



@foo{$a,$b,$c} # a slice--note the @



它的意思是



($foo{$a},$foo{$b},$foo{$c})



默认为“\034”,同 awk 的 SUBSEP

一样。如果你的散列键包含二进制数据, 可能 $;

就没法包含任何可靠的值了。

(助记:逗号(语法上的下标分隔符)是半个分号。是啊,我知道这完全没?

兴捣

2008年11月8日星期六

p2pover

什么是ARP?

我们知道,当我们在浏览器里面输入网址时,DNS服务器会自动把它解析为IP地址,浏览器实际上查找的是IP地址而不是网址。那么IP地址是如何转 换为第二层物理地址(即MAC地址)的呢?在局域网中,这是通过ARP协议来完成的。ARP协议对网络安全具有重要的意义。通过伪造IP地址和MAC地址 实现 ARP欺骗,能够在网络中产生大量的ARP通信量使网络阻塞。所以网管们应深入理解ARP协议。

一、什么是ARP协议

ARP协议是“Address Resolution Protocol”(地址解析协议)的缩写。在局域网中,网络中实际传输的是“帧”,帧里面是有目标主机的MAC地址的。在以太网中,一个主机要和另一个 主机进行直接通信,必须要知道目标主机的MAC地址。但这个目标MAC地址是如何获得的呢?它就是通过地址解析协议获得的。所谓“地址解析”就是主机在发 送帧前将目标IP地址转换成目标MAC地址的过程。ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。

二、ARP协议的工作原理

在每台安装有TCP/IP协议的电脑里都有一个ARP缓存表,表里的IP地址与MAC地址是一一对应的,如下表所示。

主机 IP地址 MAC地址
A 192.168.16.1 aa-aa-aa-aa-aa-aa
B 192.168.16.2 bb-bb-bb-bb-bb-bb

C 192.168.16.3 cc-cc-cc-cc-cc-cc
D 192.168.16.4 dd-dd-dd-dd-dd-dd

我们以主机A(192.168.1.5)向主机B(192.168.1.1)发送数据为例。

当发送数据时,主机A会在自己的ARP缓存表中寻找是否有目标 IP地址。如果找到了,也就知道了目标MAC地址,直接把目标MAC地址写入帧里面发送就可以了;如果在ARP缓存表中没有找到相对应的IP地址,主机A 就会在网络上发送一个广播,目标MAC地址是“FF.FF.FF.FF.FF.FF”,这表示向同一网段内的所有主机发出这样的询问: “192.168.1.1的MAC地址是什么?”网络上其他主机并不响应ARP询问,只有主机B接收到这个帧时,才向主机A做出这样的回应: “192.168.1.1的MAC地址是00-aa-00-62-c6-09”。这样,主机A就知道了主机B的MAC地址,它就可以向主机B发送信息了。 同时它还更新了自己的ARP缓存表,下次再向主机B发送信息时,直接从ARP缓存表里查找就可以了。ARP缓存表采用了老化机制,在一段时间内如果表中的 某一行没有使用,就会被删除,这样可以大大减少ARP缓存表的长度,加快查询速度。

三、如何查看ARP缓存表

ARP缓存表是可以查看的,也可以添加和修改。在命令提示符下,输入“arp -a”就可以查看ARP缓存表中的内容了,如附图所示。

用“arp -d”命令可以删除ARP表中某一行的内容;用“arp -s”可以手动在ARP表中指定IP地址与MAC地址的对应。

四、ARP欺骗

其实,此起彼伏的瞬间掉线或大面积的断网大都是ARP欺骗在作怪。ARP欺骗攻击已经成了破坏网吧经营的罪魁祸首,是网吧老板和网管员的心腹大患。

从影响网络连接通畅的方式来看,ARP欺骗分为二种,一种是对路由器ARP表的欺骗;另一种是对内网PC的网关欺骗。

第一种ARP欺骗的原理是——截获网关数据。它通知路由器一系列错误的内网MAC地址,并按照一定的频率不断进行,使真实的地址信息无法通过更新保存在路 由器中,结果路由器的所有数据只能发送给错误的MAC地址,造成正常PC无法收到信息。第二种ARP欺骗的原理是——伪造网关。它的原理是建立假网关,让 被它欺骗的PC向假网关发数据,而不是通过正常的路由器途径上网。在PC看来,就是上不了网了,“网络掉线了”。

一般来说,ARP欺骗攻击的后果非常严重,大多数情况下会造成大面积掉线。有些网管员对此不甚了解,出现故障时,认为PC没有问题,交换机没掉线的“本事 ”,电信也不承认宽带故障。而且如果第一种ARP欺骗发生时,只要重启路由器,网络就能全面恢复,那问题一定是在路由器了。为此,宽带路由器背了不少 “黑锅”。

作为网吧路由器的厂家,对防范ARP欺骗不得已做了不少份内、份外的工作。一、在宽带路由器中把所有PC的IP-MAC输入到一个静态表中,这叫路由器 IP-MAC绑定。二、力劝网管员在内网所有PC上设置网关的静态ARP信息,这叫PC机IP-MAC绑定。一般厂家要求两个工作都要做,称其为IP- MAC双向绑定。

五、如何实现ARP攻击?针对ARP原理的例子:

了解上面这些常识后,现在就可以谈在网络中如何实现ARP欺骗了,可以看看这样一个例子:

一个入侵者想非法进入某台主机,他知道这台主机的防火墙只对192.0.0.3(假设)这个ip开放23口(telnet),而他必须要使用telnet来进入这台主机,所以他要这么做:
1、他先研究192.0.0.3这台主机,发现这台95的机器使用一个oob就可以让他死掉。
2、于是,他送一个洪水包给192.0.0.3的139口,于是,该机器应包而死。
3、这时,主机发到192.0.0.3的ip包将无法被机器应答,系统开始更新自己的arp对应表。将192.0.0.3的项目搽去。
4、这段时间里,入侵者把自己的ip改成192.0.0.3
5、他发一个ping(icmp 0)给主机,要求主机更新主机的arp转换表。
6、主机找到该ip,然后在arp表中加入新的ip-->mac对应关系。
7、防火墙失效了,入侵的ip变成合法的mac地址,可以telnet了。

六、其他相关知识:

tcp/ip
TCP/IP协议(Transmission Control Protocol/Internet Protocol)叫做传输控制/网际协议,又叫网络通讯协议,这个协议是Internet国际互联网络的基础。

TCP/IP是网络中使用的基本的通信协议。虽然从名字上看TCP/IP包括两个协议,传输控制协议(TCP)和网际协议(IP),但TCP/IP实际上 是一组协议,它包括上百个各种功能的协议,如:远程登录、文件传输和电子邮件等,而TCP协议和IP协议是保证数据完整传输的两个基本的重要协议。通常说 TCP/IP是Internet协议族,而不单单是TCP和IP。

TCP/IP是用于计算机通信的一组协议,我们通常称它为TCP/IP协议族。它是70年代中期美国国防部为其ARPANET广域网开发的网络体系结构和 协议标准,以它为基础组建的INTERNET是目前国际上规模最大的计算机网络,正因为INTERNET的广泛使用,使得TCP/IP成了事实上的标准。

之所以说TCP/IP是一个协议族,是因为TCP/IP协议包括TCP、IP、UDP、ICMP、RIP、TELNETFTP、SMTP、ARP、TFTP等许多协议,这些协议一起称为TCP/IP协议。以下我们对协议族中一些常用协议英文名:

TCP(Transmission Control Protocol)传输控制协议

IP(Internet Protocol)网际协议

UDP(User Datagram Protocol)用户数据报协议

ICMP(Internet Control Message Protocol)互联网控制信息协议

SMTP(Simple Mail Transfer Protocol)简单邮件传输协议

SNMP(Simple Network manage Protocol)简单网络管理协议

FTP(File Transfer Protocol)文件传输协议

ARP(Address Resolation Protocol)地址解析协议

从协议分层模型方面来讲,TCP/IP由四个层次组成:网络接口层、网络层、传输层、应用层。

其中:

网络接口层 这是TCP/IP软件的最低层,负责接收IP数据报并通过网络发送之,或者从网络上接收物理帧,抽出IP数据报,交给IP层。

网络层负责相邻计算机之间的通信。其功能包括三方面。一、处理来自传输层的分组发送请求,收到请求后,将分组装入IP数据报,填充报头,选择去往 信宿机的路径,然后将数据报发往适当的网络接口。二、处理输入数据报:首先检查其合法性,然后进行寻径--假如该数据报已到达信宿机,则去掉报头,将剩下 部分交给适当的传输协议;假如该数据报尚未到达信宿,则转发该数据报。三、处理路径、流控、拥塞等问题。

传输层 提供应用程序间的通信。其功能包括:一、格式化信息流;二、提供可靠传输。为实现后者,传输层协议规定接收端必须发回确认,并且假如分组丢失,必须重新发送。

应用层向用户提供一组常用的应用程序,比如电子邮件、文件传输访问、远程登录等。远程登录TELNET使用TELNET协议提供在网络其它主机上注册的接 口。 TELNET会话提供了基于字符的虚拟终端。文件传输访问FTP使用FTP协议来提供网络内机器间的文件拷贝功能。

前面我们已经学过关于OSI参考模型的相关概念,现在我们来看一看,相对于七层协议参考模型,TCP/IP协议是如何实现网络模型的。

OSI中的层 功能 TCP/IP协议族

应用层 文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet

表示层 数据格式化,代码转换,数据加密 没有协议

会话层 解除或建立与别的接点的联系 没有协议

传输层 提供端对端的接口 TCP,UDP

网络层 为数据包选择路由 IP,ICMP,RIP,OSPF,BGP,IGMP

数据链路层 传输有地址的帧以及错误检测功能 SLIP,CSLIP,PPP,ARP,RARP,MTU

物理层 以二进制数据形式在物理媒体上传输数据 ISO2110,IEEE802。IEEE802.2

数据链路层包括了硬件接口和协议ARP,RARP,这两个协议主要是用来建立送到物理层上的信息和接收从物理层上传来的信息;

网络层中的协议主要有IP,ICMP,IGMP等,由于它包含了IP协议模块,所以它是所有机遇TCP/IP协议网络的核心。在网络层中,IP模块完成大 部分功能。ICMP和IGMP以及其他支持IP的协议帮助IP完成特定的任务,如传输差错控制信息以及主机/路由器之间的控制电文等。网络层掌管着网络中 主机间的信息传输。

传输层上的主要协议是TCP和UDP。正如网络层控制着主机之间的数据传递,传输层控制着那些将要进入网络层的数据。两个协议就是它管理这些数据的两种方 式:TCP是一个基于连接的协议(还记得我们在网络基础中讲到的关于面向连接的服务和面向无连接服务的概念吗?忘了的话,去看看);UDP则是面向无连接 服务的管理方式的协议。

应用层位于协议栈的顶端,它的主要任务就是应用了。上面的协议当然也是为了这些应用而设计的,具体说来一些常用的协议功能如下:

Telnet:提供远程登录(终端仿真)服务,好象比较古老的BBS就是用的这个登陆。

FTP :提供应用级的文件传输服务,说的简单明了点就是远程文件访问等等服务;

SMTP:不用说拉,天天用到的电子邮件协议。

TFTP:提供小而简单的文件传输服务,实际上从某个角度上来说是对FTP的一种替换(在文件特别小并且仅有传输需求的时候)。

SNTP:简单网络管理协议。看名字就不用说什么含义了吧。

DNS:域名解析服务,也就是如何将域名映射城IP地址的协议。

HTTP:不知道各位对这个协议熟不熟悉啊?这是超文本传输协议,你之所以现在能看到网上的图片,动画,音频,等等,都是仰仗这个协议在起作用啊!

2008年11月7日星期五

zzVim的编码及字体问题详解

Vim的编码及字体问题详解

2007-07-30 09:58:19 Linux联盟收集整理

和所有的流行文本编辑器一样,Vim 可以很好的编辑各种字符编码的文件,这当然包括UCS-2、UTF-8 等流行的 Unicode 编码方式。然而不幸的是,和很多来自 Linux 世界的软件一样,这需要你自己动手设置。

Vim 有四个跟字符编码方式有关的选项,encoding、fileencoding、fileencodings、termencoding (这些选项可能的取值请参考 Vim 在线帮助 :help encoding-names),它们的意义如下:

* encoding: Vim 内部使用的字符编码方式,包括 Vim 的 buffer (缓冲区)、菜单文本、消息文本等。默认是根据你的locale选择.用户手册上建议只在 .vimrc 中改变它的值,事实上似乎也只有在.vimrc 中改变它的值才有意义。你可以用另外一种编码来编辑和保存文件,如你的vim的encoding为utf-8,所编辑的文件采用cp936编码,vim会 自动将读入的文件转成utf-8(vim的能读懂的方式),而当你写入文件时,又会自动转回成cp936(文件的保存编码).

* fileencoding: Vim 中当前编辑的文件的字符编码方式,Vim 保存文件时也会将文件保存为这种字符编码方式 (不管是否新文件都如此)。

* fileencodings: Vim自动探测fileencoding的顺序列表, 启动时会按照它所列出的字符编码方式逐一探测即将打开的文件的字符编码方式,并且将 fileencoding 设置为最终探测到的字符编码方式。因此最好将Unicode 编码方式放到这个列表的最前面,将拉丁语系编码方式 latin1 放到最后面。

* termencoding: Vim 所工作的终端 (或者 Windows 的 Console 窗口) 的字符编码方式。如果vim所在的term与vim编码相同,则无需设置。如其不然,你可以用vim的termencoding选项将自动转换成term 的编码.这个选项在 Windows 下对我们常用的 GUI 模式的 gVim 无效,而对 Console 模式的Vim 而言就是 Windows 控制台的代码页,并且通常我们不需要改变它。

好了,解释完了这一堆容易让新手犯糊涂的参数,我们来看看 Vim 的多字符编码方式支持是如何工作的。

1. Vim 启动,根据 .vimrc 中设置的 encoding 的值来设置 buffer、菜单文本、消息文的字符编码方式。

2. 读取需要编辑的文件,根据 fileencodings 中列出的字符编码方式逐一探测该文件编码方式。并设置 fileencoding 为探测到的,看起来是正确的 (注1) 字符编码方式。

3. 对比 fileencoding 和 encoding 的值,若不同则调用 iconv 将文件内容转换为encoding 所描述的字符编码方式,并且把转换后的内容放到为此文件开辟的 buffer 里,此时我们就可以开始编辑这个文件了。注意,完成这一步动作需要调用外部的 iconv.dll(注2),你需要保证这个文件存在于 $VIMRUNTIME 或者其他列在 PATH 环境变量中的目录里。

4. 编辑完成后保存文件时,再次对比 fileencoding 和 encoding 的值。若不同,再次调用 iconv 将即将保存的 buffer 中的文本转换为 fileencoding 所描述的字符编码方式,并保存到指定的文件中。同样,这需要调用 iconv.dll由于 Unicode 能够包含几乎所有的语言的字符,而且 Unicode 的 UTF-8 编码方式又是非常具有性价比的编码方式 (空间消耗比 UCS-2 小),因此建议 encoding 的值设置为utf-8。这么做的另一个理由是 encoding 设置为 utf-8 时,Vim 自动探测文件的编码方式会更准确 (或许这个理由才是主要的 ;)。我们在中文 Windows 里编辑的文件,为了兼顾与其他软件的兼容性,文件编码还是设置为 GB2312/GBK 比较合适,因此 fileencoding 建议设置为 chinese (chinese 是个别名,在 Unix 里表示 gb2312,在 Windows 里表示cp936,也就是 GBK 的代码页)。

以 下是我的 .vimrc(见附件) 中关于字符编码方式设置的内容,这个设置比较有弹性,可以根据系统中的环境变量 $LANG (当然,Windows 中的写法是 %LANG%) 的值来自动设置合适的字符编码方式。此时,推荐设置 %LANG% = zh_CN.UTF-8,可以通过后面的 Windows 注册表脚本文件来方便的做到。

注1: 事实上,Vim 的探测准确度并不高,尤其是在 encoding 没有设置为 utf-8 时。因此强烈建议将 encoding 设置为 utf-8,虽然如果你想 Vim 显示中文菜单和提示消息的话这样会带来另一个小问题。

注2: 在 GNU 的 FTP 上可以下载到 iconv 的 Win32 版(http://mirrors.kernel.org/gnu/libiconv/libiconv-1.9.1.bin.woe32.zip),不 推荐去GnuWin32(http://gnuwin32.sourceforge.net/) 下载 libiconv,因为那个版本旧一些,并且需要自己改名 dll 文件。

注3: 查看帮助 :h iconv-dynamic

On MS-Windows Vim can be compiled with the |+iconv/dyn| feature. This means

Vim will search for the "iconv.dll" and "libiconv.dll" libraries. When

neither of them can be found Vim will still work but some conversions won't be

possible.

附1:vimrc文件

" Multi-encoding setting, MUST BE IN THE BEGINNING OF .vimrc!
"
if has("multi_byte")
" When 'fileencodings' starts with 'ucs-bom', don't do this manually
"set bomb
set fileencodings=ucs-bom,chinese,taiwan,japan,korea,utf-8,latin1
" CJK environment detection and corresponding setting
if v:lang =~ "^zh_CN"
" Simplified Chinese, on Unix euc-cn, on MS-Windows cp936
set encoding=chinese
set termencoding=chinese
if &fileencoding == ''
set fileencoding=chinese
endif
elseif v:lang =~ "^zh_TW"
" Traditional Chinese, on Unix euc-tw, on MS-Windows cp950
set encoding=taiwan
set termencoding=taiwan
if &fileencoding == ''
set fileencoding=taiwan
endif
elseif v:lang =~ "^ja_JP"
" Japanese, on Unix euc-jp, on MS-Windows cp932
set encoding=japan
set termencoding=japan
if &fileencoding == ''
set fileencoding=japan
endif
elseif v:lang =~ "^ko"
" Korean on Unix euc-kr, on MS-Windows cp949
set encoding=korea
set termencoding=korea
if &fileencoding == ''
set fileencoding=korea
endif
endif
" Detect UTF-8 locale, and override CJK setting if needed
if v:lang =~ "utf8$" || v:lang =~ "UTF-8$"
set encoding=utf-8
endif
else
echoerr 'Sorry, this version of (g)Vim was not compiled with "multi_byte"'
endif

附2:

Supported 'encoding' values are:                        *encoding-values*
1 latin1 8-bit characters (ISO 8859-1)
1 iso-8859-n ISO_8859 variant (n = 2 to 15)
1 koi8-r Russian
1 koi8-u Ukrainian
1 macroman MacRoman (Macintosh encoding)
1 8bit-{name} any 8-bit encoding (Vim specific name)
1 cp437 similar to iso-8859-1
1 cp737 similar to iso-8859-7
1 cp775 Baltic
1 cp850 similar to iso-8859-4
1 cp852 similar to iso-8859-1
1 cp855 similar to iso-8859-2
1 cp857 similar to iso-8859-5
1 cp860 similar to iso-8859-9
1 cp861 similar to iso-8859-1
1 cp862 similar to iso-8859-1
1 cp863 similar to iso-8859-8
1 cp865 similar to iso-8859-1
1 cp866 similar to iso-8859-5
1 cp869 similar to iso-8859-7
1 cp874 Thai
1 cp1250 Czech, Polish, etc.
1 cp1251 Cyrillic
1 cp1253 Greek
1 cp1254 Turkish
1 cp1255 Hebrew
1 cp1256 Arabic
1 cp1257 Baltic
1 cp1258 Vietnamese
1 cp{number} MS-Windows: any installed single-byte codepage
2 cp932 Japanese (Windows only)
2 euc-jp Japanese (Unix only)
2 sjis Japanese (Unix only)
2 cp949 Korean (Unix and Windows)
2 euc-kr Korean (Unix only)
2 cp936 simplified Chinese (Windows only)
2 euc-cn simplified Chinese (Unix only)
2 cp950 traditional Chinese (on Unix alias for big5)
2 big5 traditional Chinese (on Windows alias for cp950)
2 euc-tw traditional Chinese (Unix only)
2 2byte-{name} Unix: any double-byte encoding (Vim specific name)
2 cp{number} MS-Windows: any installed double-byte codepage
u utf-8 32 bit UTF-8 encoded Unicode (ISO/IEC 10646-1)
u ucs-2 16 bit UCS-2 encoded Unicode (ISO/IEC 10646-1)
u ucs-2le like ucs-2, little endian
u utf-16 ucs-2 extended with double-words for more characters
u utf-16le like utf-16, little endian
u ucs-4 32 bit UCS-4 encoded Unicode (ISO/IEC 10646-1)
u ucs-4le like ucs-4, little endian

The {name} can be any encoding name that your system supports. It is passed
to iconv() to convert between the encoding of the file and the current locale.
For MS-Windows "cp{number}" means using codepage {number}.

Several aliases can be used, they are translated to one of the names above.
An incomplete list:

1 ansi same as latin1 (obsolete, for backward compatibility)
2 japan Japanese: on Unix "euc-jp", on MS-Windows cp932
2 korea Korean: on Unix "euc-kr", on MS-Windows cp949
2 prc simplified Chinese: on Unix "euc-cn", on MS-Windows cp936
2 chinese same as "prc"
2 taiwan traditional Chinese: on Unix "euc-tw", on MS-Windows cp950
u utf8 same as utf-8
u unicode same as ucs-2
u ucs2be same as ucs-2 (big endian)
u ucs-2be same as ucs-2 (big endian)
u ucs-4be same as ucs-4 (big endian)
default stands for the default value of 'encoding', depends on the
environment



http://www.xxlinux.com/linux/article/accidence/technique/20070730/9171.html

//-------------------------------------------------------------------------------------------



http://www.pmme.cn/archives/the-encoding-of-vim/

一般的,vim打开中文文件时会出现乱码,原因比较复杂,不罗嗦了。直接讲解决办法

set fileencoding=gb18030
set fileencodings=utf-8,gb18030,utf-16,big5

想看这样设置的原因吗?请继续。下文在网络中广泛流传

vim里面的编码主要跟三个参数有关:enc(encoding), fenc(fileencoding)和fencs(fileencodings)

其中fenc是当前文件的编码,也就是说,一个在vim里面已经正确显示了的文件(前提是你的系统环境跟你的enc设置匹配),你可以通过改变 fenc后再w来将此文件存成不同的编码。比如说,我:set fenc=utf-8然后:w就把文件存成utf-8的了,:set fenc=gb18030再:w就把文件存成gb18030的了。这个值对于打开文件的时候是否能够正确地解码没有任何关系。

fencs就是用来在打开文件的时候进行解码的猜测列表。文件编码没有百分百正确的判断方法,所以vim只能猜测文件编码。比如我的vimrc里面这个的设置是

set fileencodings=utf-8,gb18030,utf-16,big5

所以我的vim每打开一个文件,先尝试用utf-8进行解码,如果用utf-8解码到了一半出错(所谓出错的意思是某个地方无法用utf-8正确地解 码),那么就从头来用gb18030重新尝试解码,如果gb18030又出错(注意gb18030并不是像utf-8似的规则编码,所以所谓的出错只是说 某个编码没有对应的有意义的字,比如0),就尝试用utf-16,仍然出错就尝试用big5。这一趟下来,如果中间的某次解码从头到尾都没有出错,那么 vim就认为这个文件是这个编码的,不会再进行后面的尝试了。这个时候,fenc的值就会被设为vim最后采用的编码值,可以用:set fenc?来查看具体是什么。

当然这个也是有可能出错的,比如你的文件是gb18030编码的,但是实际上只有一两个字符是中文,那么有可能他们正好也能被utf-8解码,那么这个文件就会被误认为是utf-8的导致错误解码。

至于enc,其作用基本只是显示。不管最后的文件是什么编码的,vim都会将其转换为当前系统编码来进行处理,这样才能在当前系统里面正确地显示出来,因 此enc就是干这个的。在windows下面,enc默认是cp936,这也就是中文windows的默认编码,所以enc是不需要改的。在 linux下,随着你的系统locale可能设为zh_CN.gb18030或者zh_CN.utf-8,你的enc要对应的设为gb18030或者 utf-8(或者gbk之类的)。

最后再来说一下新建空文件的默认编码。看文档好像说会采用fencs里面的第一个编码作为新建文件的默认编码。但是这里有一个问题,就是fencs 的顺序跟解码成功率有很大关系,根据我的经验utf-8在前比gb18030在前成功率要高一些,那么如果我新建文件默认想让它是gb18030编码怎么 办?一个方法是每次新建文件后都:set fenc=gb18030一下,不过我发现在vimrc里面设置fenc=gb18030也能达到这个效果。

另外,在ubuntu中文论坛还有人提出了这样的办法,直接就配置了

所有代码直接粘贴到终端运行即可!
安装程序
代码:
sudo apt-get install vim-gtk vim-doc cscope

创建启动项
代码:

cat > /usr/share/applications/gvim.desktop < $HOME/.vimrc << “EOF”
“===========================================================================
” 项目: gvim 配置文件
” 作者: yonsan [QQ:82555472]
” 安装: sudo apt-get install vim-gtk
” 用法: 将本文件(.vimrc)拷贝到$HOME/
“===========================================================================

” 使用 murphy 调色板
colo murphy
” 设置用于GUI图形用户界面的字体列表。
set guifont=SimSun 10

set nocompatible
” 设定文件浏览器目录为当前目录
set bsdir=buffer
set autochdir
” 设置编码
set enc=utf-8
” 设置文件编码
set fenc=utf-8
” 设置文件编码检测类型及支持格式
set fencs=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936
” 指定菜单语言
set langmenu=zh_CN.UTF-8
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim
” 设置语法高亮度
set syn=cpp
“显示行号
set nu!
” 查找结果高亮度显示
set hlsearch
” tab宽度
set tabstop=4
set cindent shiftwidth=4
set autoindent shiftwidth=4
” C/C++注释
set comments=://
” 修正自动C式样注释功能
set comments=s1:/*,mb:*,ex0:/
” 增强检索功能
set tags=./tags,./../tags,./**/tags
” 保存文件格式
set fileformats=unix,dos
” 键盘操作
map gk
map gj
” 命令行高度
set cmdheight=1
” 使用cscope
if has(”cscope”)
set csprg=/usr/bin/cscope
set csto=0
set cst
set nocsverb
” add any database in current directory
if filereadable(”cscope.out”)
cs add cscope.out
” else add database pointed to by environment
elseif $CSCOPE_DB != “”
cs add $CSCOPE_DB
endif
set csverb
endi
” 中文帮助
if version > 603
set helplang=cn
endi
EOF

locale为zh_CN.gbk的配置文件
代码:

cat > $HOME/.vimrc << “EOF”
“===========================================================================
” 项目: gvim 配置文件
” 作者: yonsan [QQ:82555472]
” 安装: sudo apt-get install vim-gtk
” 用法: 将本文件(.vimrc)拷贝到$HOME/
“===========================================================================

” 使用 murphy 调色板
colo murphy
” 设置用于GUI图形用户界面的字体列表。
set guifont=SimSun 10

set nocompatible
” 设定文件浏览器目录为当前目录
set bsdir=buffer
set autochdir
” 设置编码
set enc=chinese
” 设置文件编码
set fenc=chinese
” 设置文件编码检测类型及支持格式
set fencs=gbk,utf-8,ucs-bom,gb18030,gb2312,cp936
” 指定菜单语言
set langmenu=zh_CN.GBK
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim
” 设置语法高亮度
set syn=cpp
“显示行号
set nu!
” 查找结果高亮度显示
set hlsearch
” tab宽度
set tabstop=4
set cindent shiftwidth=4
set autoindent shiftwidth=4
” C/C++注释
set comments=://
” 修正自动C式样注释功能
set comments=s1:/*,mb:*,ex0:/
” 增强检索功能
set tags=./tags,./../tags,./**/tags
” 保存文件格式
set fileformats=unix,dos
” 键盘操作
map gk
map gj
” 命令行高度
set cmdheight=1
” 使用cscope
if has(”cscope”)
set csprg=/usr/bin/cscope
set csto=0
set cst
set nocsverb
” add any database in current directory
if filereadable(”cscope.out”)
cs add cscope.out
” else add database pointed to by environment
elseif $CSCOPE_DB != “”
cs add $CSCOPE_DB
endif
set csverb
endi
” 中文帮助
if version > 603
set helplang=cn
endi

EOF

2008年10月13日星期一

豆瓣挂了,

我日,
豆瓣挂了,
几秒前还好的。。。
081013/18:13:35

test

doubanclaim84968bf3654b7d27

test

test

2008年10月11日星期六

2008年10月8日星期三

淡淡的绿色

设置方法:打开控制面板中的"显示" 选择外观(appearance)-高级(advanced),然后在项目(items)那栏选窗口(windows),再点颜色(color)-其它(others),然后把Hue(色调设为85,Sat(饱和度)设为90,Lum(亮度)设为205。

2008年9月27日星期六

实模式 保护模式和虚拟86模式

首先,80386以及80386以后的CPU都是32位的

纯32位windows是不能进入实模式的,重启以后到载入WINDOWS以前都是实模式,也许你会说windows98不是是可以不用重启机器直接进入到纯DOS(实模式)下么

首先,98是个16位和32混编的系统,所以不稳定,但对游戏支持甚好,而且其内核是建立在16位上的(你要是搞过Win32编程就会有所了解),这样的话进入DOS很方便,或者在DOS下一条win命令就可以进入WINDOWS...

但是从NT开始就不行了,2000/XP都是建立在纯32位(NT开始)内核上的,所以很稳定,但是如果不重新启动到DOS下是不能进行实模式操作的,但是考虑程序的兼容问题,为了让以前的16位程序能在32位下运行,80386就提供了虚拟86模式(这和windows无关,是CPU提供的模式,另外可以告诉你,因为80286没有虚拟86模式,只有实模式和保护模式,当时一些流行的16位程序要使用的话必须重启到DOS下,再进到到保护模式),虚拟86模式实际上就是模拟16位的8086
CPU的实模式,但这和实模式有很大区别,最大的因该算是中断被屏蔽或转为windows的异常处理了,这样你要用诸如:int 13h 命令是行不通的,因为windows是建立在保护模式上的,保护模式下有自己的中断模式,如果你要从windows进入实模式的话只有重新启动再到DOS 下了。

现在几乎不需要进入实模式了,除非你windows中了毒不能进入,到DOS下重装/恢复/备份系统,还有就是一些硬件底层的破解啦,比如破解还原卡之类的。

进入保护模式是每个32位系统必须的,因为这样系统才能才能利用保护模式提供的保护机制管理和维护自己,程序也就稳定了,

虚拟86模式没什么需要不需要,CPU提供这个模式,程序是16位的时候,系统会自动加载到虚拟86模式中运行...

我们在windows下打开的cmd(别忘了98下叫MS-DOS方式,这个模式仍是在16的内核上,而从NT开始的CMD就是纯32位了!!!!)它在系统中的定义是字符模式(非窗口),这样给一些16位的程序提供了运行环境....

2008年9月26日星期五

How to Determine Text File Encoding

With the explosion of international text resources brought by the Internet, the standards for determining file encodings have become more important. This is my attempt at making the text file encoding issues digestible by leaving out some of the unimportant anecdotal stuff. I'm also calling attention to blunders in the MSDN docs.

For Unicode files, the BOM ("Byte Order Mark" also called the signature or preamble) is a set of 2 or so bytes at the beginning used to indicate the type of Unicode encoding. The key to the BOM is that it is generally not included with the content of the file when the file's text is loaded into memory, but it may be used to affect how the file is loaded into memory. Here are the most important BOMs and the encodings they indicate:

  • FF FE UCS-2LE or UTF-16LE
  • FE FF UCS-2BE or UTF-16BE
  • EF BB BF UTF-8

BOM stands for Byte Order Mark which literally is meant to distinguish between little-endian LE and big-endian BE byte order by representing the code point U+FEFF ("zero width no-break space"). Since 0xFFFE (bytes swapped) is not a valid Unicode character, you can be sure of the byte order. Note that the BOM does not distinguish between UCS-2 and UTF-16 (they are the same except that UTF-16 has surrogate pairs to represent more code points). The UTF-8 BOM is not concerned with "byte order," but it is a unique enough sequence (representing the same U+FEFF code point) that would be very unlikely to be found in a non-UTF-8 file, thus distinguishing UTF-8 especially from other "ASCII-based" encodings.

The BOM is not guaranteed to be in every Unicode file. In fact the BOM is not necessary in XML files because the Unicode encoding can be determined from the leading less than sign. If the first byte is an ASCII less than sign 3C followed by a non-zero byte then the file is assumed to be UTF-8 until otherwise specified in the XML Declaration. If the XML file begins with 3C 00 it is UCS-2LE or UTF-16LE (normal for Windows Unicode files). If the XML file begins with 00 3C it is UCS-2BE or UTF-16BE. In summary then:

  • 3C 00 UCS-2LE or UTF-16LE
  • 00 3C UCS-2BE or UTF-16BE
  • 3C XX UTF-8 (where XX is non-zero)

Unlike the BOM, these bytes are part of the text content of the file.

Also, the BOM is not used to determine non-Unicode encodings such as Windows-1250, GB2312, Shift-JIS, or even EBCDIC. Generally you should have some way of knowing the encoding due to the context of your situation. However, markup languages have ways of specifying the encoding in the markup near the top of the file. The following appears inside the area of an HTML page:

charset=utf-8" />

In XML, the XML declaration specifies the encoding.

encoding="iso-8859-1"?>

This works because all of the encodings are compatible enough with ASCII in the lower 128, so the encoding can be specified as an ASCII string. The alternative to ASCII is EBCDIC; if an XML file begins with the EBCDIC less than sign 4C it is treated as EBCDIC and the XML declaration (if present) would be processed in standard EBCDIC to determine the extended EBCDIC variant.

If I hadn't seen fundamental problems in Microsoft documentation before it would be inconceivable to me that in articles about the Unicode BOM, the BOM is shown backwards, but it is true! Both the Byte-order Mark and IsTextUnicode MSDN articles get the UTF-16 BOM bytes backwards. Herfried K. Wagner [MVP] agreed that the documentation is wrong (plain as day but it is still good to be MVP corroborated).

Another thing that irks me is the IsTextUnicode API. This API is so useless it bears mentioning. First of all, it does not deal with UTF-8, so it can only be one part of the way Notepad detects Unicode. Raymond Chen said it is used in Notepad but Notepad actually auto-detects UTF-8 as explained below (his blog, The Old New Thing is one of my three favorites). Secondly, when text is in memory, it should usually not have the BOM with it since it can only be efficient to interrogate the BOM before loading the file. Thirdly, if you cannot guarantee the statistical analysis, you are better off using a simple deterministic mechanism that you can explain to the end user so that they don't experience seemingly erratic behavior.

UTF-8 auto-detection (when there is no UTF-8 BOM) is not widely documented (although it is exhibited by Windows Notepad). UTF-8 multi-byte sequences have a pattern that would be almost impossible to accidentally produce in another encoding. The more non-ASCII characters a UTF-8 file has, the more certain you can be that it is UTF-8, but my impression is that you don't need many.

Without going into the full algorithm, just perform UTF-8 decoding on the file looking for an invalid UTF-8 sequence. The correct UTF-8 sequences look like this:

  • 0xxxxxxx ASCII <>
  • 110xxxxx 10xxxxxx 2-byte >= 0x80
  • 1110xxxx 10xxxxxx 10xxxxxx 3-byte >= 0x400
  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4-byte >= 0x10000

If the file is all ASCII, you cannot know if it was meant to be UTF-8 or any other character set compatible with ASCII in the lower 128.

Without contextual information, a BOM, or a file type standard with a header like XML and HTML, a file should be assumed to be in the default system locale ANSI code page, governed by the Language for non-Unicode Programs in the Regional Settings on the computer on which it is found.

2008年9月3日星期三

VB为office编写插件

http://www.cnblogs.com/szyicol/archive/2006/10/26/540248.html

通过此演练,可以用 VB 创建 COM 加载项。COM
加载项可以在不给用户增加复杂性的情况下扩展应用程序的功能。究其实质,COM
加载项是一个动态链接库 (DLL),需要进行注册才能供 Microsoft?
Office XP
应用程序加载和使用。虽然可以将加载项编写成可执行文件
(.exe),但 DLL 通常会比.exe 文件提供更好的性能。

  此演练将使用 VB 创建并运行一个自定义工具栏 COM
加载项。本主题中的任务假定您熟悉 Office 应用程序、VB
工程,以及调试和运行代码。

  引言

  创建 COM 加载项时可以使用任何支持 COM 的语言,如 VBA、Visual
Basic 和 Microsoft Visual C 。用 Office Developer
创建的加载项将自动打包成 DLL,并由宿主应用程序注册后进行加载。可以创建一个加载项但能用于多个应用程序中。有关详细信息。请参阅为多个应用程序创建
COM 加载项。

  此演练将完成一系列步骤,从而用 VB 创建一个 COM
加载项。创建 COM 加载项的基本步骤包括:

  1.配置外接程序设计器。

  2.在外接程序设计器中编写代码。

  3.将命令条控件集成到加载项中。

  4.对 COM 加载项进行调试和测试。

  5.为 COM 加载项生成 DLL。

  6.解决 COM 加载项的开发问题。

  配置外接程序设计器

  用外接程序设计器创建的工程为开发加载项提供工作区域。使用外接程序设计器可以创建用于
VBA 或任何 Office 应用程序的 COM
加载项。工程中的每个外接程序设计器都表示一个单独的、只能在一种
Office 应用程序中运行的加载项。创建的 DLL
可包含多个加载项,它们使用相同的窗体、模块和类模块,但面向的却是不同的应用程序。此演练使用
Excel 作为宿主 Office 应用程序。

  如果希望加载项可供多个应用程序使用,就必须为每个宿主应用程序各自添加一个外接程序设计器。可以通过模块共享代码;但在每个工程中,必须引用每个宿主应用程序所特定的对象模型。

  配置外接程序设计器

  1.打开 VB

  2.在“文件”菜单中,选择“新建工程”,然后选择“外接程序”。

  3.把窗体移除,双击设计器中的Connect。

  3.在“外接程序显示名称”文本框中键入名称 Greeting
Toolbar,在“外接程序描述”文本框中键入说明 Toolbar add-in
that launches a Hello World message in Excel。

  4.从“应用程序”列表中选择 Microsoft Excel。

  5.从“应用程序版本”列表中选择 Microsoft Excel 10.0。

  6.从“初始化加载行为”列表中选择 "Startup"。有关各种不同类型初始加载行为的详细信息,请参阅指定加载行为。

  此主题相关图片如下:

  7.在“工程”菜单中,选择“引用”,确保让工程引用下列类型库。(该引用列表是此演练所必需的。对于您的加载项,要确保选择每个可以使用加载项的
Office 应用程序所需的类型库。)

●Visual Basic for Applications

●OLE Automation

●Microsoft Add-in Designer

●Microsoft Office 10.0 Object Library

●Microsoft Excel 10.0 Object Library

  8.在“文件”菜单中选择“保存 Connect”。

  9.在“工程另存为”对话框中,输入名称 Greetings.Dsr,选择要将其保存到的文件夹,然后单击“保存”。


  在外接程序设计器中编写代码

  在创建工程并为外接程序设计器赋值后,可以添加代码将加载项与宿主应用程序连接起来。此演练将向您展示将加载项与宿主应用程序连接起来所需的典型过程和事件。IDTExtensibility2
接口提供连接这二者所需的 COM
对象和事件。然后,加载项可以使用宿主应用程序所展示的对象模型与宿主应用程序接合。可以在对象浏览器中查看特定应用程序的对象模型。

  外接程序设计器中的代码可处理加载项与宿主应用程序的集成。例如,加载或卸载加载项时运行的代码驻留在“外接程序设计器”的模块中。如果加载项中包含窗体,则外接程序设计器还可以包含用于显示窗体的代码。

  声明变量和设置过程存根

  1.在“工程资源管理器”窗口中,选择 Connect,然后打开“视图”菜单,单击“代码”。清除原来有的代码。

  2.在“通用声明”部分,引用可扩展性接口。

Implements IDTExtensibility2

  3.添加用于在加载项和宿主之间提供通讯的模块级变量。只要加载了
COM 加载项,赋值为 As Excel.Application
的变量就一直存在,因此,所有过程都可以确定加载项当前正在哪个应用程序中运行。因为
WithEvents 关键字指派给 cbbButton 变量,所以菜单项的 Click
事件过程将在用户单击新菜单项时触发。


'Global object references

Public appHostApp As Excel.Application

Private WithEvents cbbButton As Office.CommandBarButton


  4.在“代码”窗口中,从“对象”列表中选择
IDTExtensibility2,从“事件”列表中选择 OnConnection。这将创建
OnConnection 事件过程存根。

注意 您必须使由 IDTExtensibility2
界面提供的每个事件中都包括事件过程存根。如果您删除了任何事件过程,工程就无法编译。

  5.为下列每个事件添加事件过程存根:

●OnDisconnection

●OnStartupComplete

●OnBeginShutdown

●OnAddinsUpdate

  现在就可以为您的加载项添加功能了。


  将命令条控件集成到加载项中

  如果您的 COM
加载项有一个用户界面,就可以添加用于显示命令条的代码,以方便用户运行您的加载项。此演练将显示如何在宿主应用程序中包含用于创建新命令条控件(工具栏按钮或菜单项)的代码。加载您的加载项时,会同时加载控件,用户可以通过单击按钮或菜单项打开并使用加载项。

  创建命令条控件

  1.查找 OnConnection 事件过程。在 Private Sub 和 End Sub
行之间,添加代码以创建新的命令条控件并将其指派给支持事件的
CommandBarButton 对象变量。整个过程将显示如下:


Private Sub IDTExtensibility2_OnConnection(ByVal _

Application As Object, ByVal ConnectMode As _

AddInDesignerObjects.ext_ConnectMode, ByVal AddInInst _

As Object, custom() As Variant)

' 存储启动引用

Set appHostApp = Application

' 添加命令条

Set cbbButton = CreateBar()

End Sub


  如果您熟悉使用 Visual Basic
创建加载项,就可能注意到,在 VBA
中创建加载项时,不用设置命令条按钮 OnAction
属性的值。这是因为事件自动为您挂起。

  2.查找 OnDisconnection 事件过程。在 Private Sub 和 End Sub
行之间,添加代码以便在卸载加载项时删除命令条控件。整个过程将显示如下:


Private Sub IDTExtensibility2_OnDisconnection(ByVal _

RemoveMode As AddInDesignerObjects.ext_DisconnectMode, _

custom() As Variant)

RemoveToolbar

' 移除要关闭的引用

Set appHostApp = Nothing

Set cbbButton = Nothing

End Sub


  3.通常,只要在代码中存储函数,就会在 OnConnection
过程中添加您调用的函数对应的代码。该函数将创建命令条,设置命令按钮的属性,并提供错误信息的处理。


Public Function CreateBar() As Office.CommandBarButton

' 指定命令条

Dim cbcMyBar As Office.CommandBar

Dim btnMyButton As Office.CommandBarButton

On Error GoTo CreateBar_Err

Set cbcMyBar = appHostApp.CommandBars.Add(Name:="GreetingBar")

' 指定命令条按钮

Set btnMyButton = cbcMyBar.Controls.Add(Type:=msoControlButton, _

Parameter:="Greetings")

With btnMyButton

.Style = msoButtonCaption

.BeginGroup = True

.Caption = "&Greetings"

.TooltipText = "Display Hello World Message"

.Width = "24"

End With

' 显示并返回命令条

cbcMyBar.Visible = True

Set CreateBar = btnMyButton

Exit Function

CreateBar_Err:

MsgBox Err.Number & vbCrLf & Err.Description

End Function


  4.在 OnDisconnection
过程中添加您调用的函数对应的代码。该函数在加载宏被卸载时会删除命令条。


Private Function RemoveToolbar()

 appHostApp.CommandBars("GreetingBar").Delete

End Function


  5.为 CommandBarButton
对象添加一个单击事件过程。该过程将在单击新的命令条按钮时被调用。下面的代码将显示一条消息以表明单击事件正在进行:


Private Sub cbbButton_Click(ByVal Ctrl As Office.CommandBarButton,
CancelDefault As Boolean)

 MsgBox ("Hello World!")

End Sub


  6.保存您的工程。

  现在,COM
加载项完成。其余的步骤就是调试和测试代码以确保它运行顺利,然后将加载项放入
DLL 文件中,该文件可以在其他装有 Office XP
的计算机上进行分发和使用。


  对加载项进行调试和测试

  当您在 VB 中开发 COM
加载项时,可以通过将工程置于运行模式而调试加载项。如果工程处于运行模式,就可以从
Office 应用程序中加载 COM 加载项并使用它,通过使用任何 VB
调试工具而对它进行测试和调试。

  使用 VB 调试和测试 COM 加载项

  1.将任何所需的断点、Stop 语句或监视放在代码中。(可先不做这步)

  2.在“工程”菜单上,单击“属性”,在“调试”对话框中,选择“等待要创建的部件”,单击“确定”

  3.在“运行”菜单上,单击“全编译执行”。这将对工程进行编译(当出现任何编译错误时将提出警告),然后将工程置于运行模式。

  4.检查“[运行]”是否出现在VB的标题栏中。

  注意 必须发布加载项,宿主应用程序才能使用它。

  4.启动一个新的 Excel
实例。因为将加载项的加载行为设为 "Startup",所以只要启动应用程序,加载项就会加载,OnConnection
事件就会发生,于是出现 Greetings
按钮。现在,您可以使用为调试代码而添加的断点和 Stop
语句了。

  如果单击 Greetings 按钮,则只要在 VB 中运行工程,Hello
World 消息就会出现在编辑器之前(不在 Excel
之前)。在将工程生成为 DLL 文件后,该消息就会出现在 Excel
之前。

  5.当完成调试和测试后,打开“运行”菜单,单击“终止工程”。这会清除临时文件和注册表项,并将工程置于正确的状态以生成
DLL 文件。

  为 COM 加载项生成 DLL

  编写并调试代码后,可以使您的加载项成为一个 DLL
以将其部署到其他装有 Office XP 的计算机上。

  在 VB 中将 COM 加载项打包为 DLL

  1.从“文件”菜单上,选择“生成 myAddin.DLL”。

  2.在“生成工程”对话框中保存文件名 Greetings,并选择要用于保存工程的位置。

  3.单击“确定”。 (此时,加载项可在本机正式使用)

  这一步骤将创建 COM 加载项,添加适当的注册表项,并使COM
加载项可用于 Office 宿主中。创建加载项 DLL 时,VB
使用给外接程序设计器提供的信息,将 DLL 注册为 COM
加载项。VB
向注册表中写入加载项的名称、说明和初始加载行为设置。加载项的宿主应用程序读取这些注册表项并加载相应的加载项。

  常见加载项开发问题疑难解答

  当在开发环境中工作并在应用程序之间进行切换时,可能会遇到某些错误信息或意外行为。下面是一些常见问题及其解决方案。

  出现编译错误或语句结束在编辑器中无效

  要确保为工程引用了适当的对象库。

  运行工程并打开新的宿主应用程序实例时没有任何反应

 

  ●要确保字“已发布的”出现在所运行的加载项的标题栏中。如果不如此,就必须运行工程。

  ●单击每个打开的应用程序窗口。您的对象可能正在运行,但只有在您单击所打开的应用程序的第一个实例时,它才是可见的。

  ●要确保正确地指定并设置模块级变量。

  ●在宿主应用程序中,要确保在“COM 加载项”对话框中选中了您的加载项。可以通过向工具栏中添加
COM 加载项命令而对宿主应用程序进行自定义。此命令将打开“COM
加载项”对话框。

  将 COM 加载项对话框添加到工具栏中

  1.打开EXCEL“工具”菜单,单击“自定义”,选择“命令”选项卡。在“类别”下,选择“工具”。沿“命令”列表向下滚动,以查找“COM
加载项”。将“COM 加载项”拖动到工具栏中,以创建新的按钮,然后关闭“自定义”对话框。

  2.在该工具栏上,单击刚添加的“COM 加载项”按钮。

  3.在“COM 加载项”对话框中,确认选中您的加载项旁边的复选框。若要卸载加载项,请清除该复选框。

  对象出现在宿主应用程序中但没有响应

  可能是有多个对象实例在运行。用于检测和移除已有的具有该名称的代码可能没在运行。检查并调试您的
OnDisconnection 代码。

--------------------------------------------------------.

another:http://www.excelperfect.com/2008/06/08/%E4%BD%BF%E7%94%A8vb6%E7%BC%96%E5%86%99com%E5%8A%A0%E8%BD%BD%E9%A1%B9/

Office Addin 自动化(Automation)基础概念

http://www.winxgui.cn/blog/?p=101

自动化(Automation)基础概念:二次开发接口(API)与插件(Addin)

在前文,我们已经解释了:

而同时,我们经常也可能经常听到以下这些词语:

  • 自动化(Automation,COM Automation)
  • OA(办公自动化,Office Automation)
  • 二次开发接口(应用程序开发接口,Application Programming Interface,API)
  • 插件(Addin,Addon)

等等。本文试图解释这些概念。

自动化(Automation)顾名思义是指“让机器在没有人工干预的情况下自动完成特定的任务”。为了完成这一目标,自动化(Automation)技术的核心想法是,应用程序(Application)需要把自己的核心功能以DOM模型的形式对外提供,使得别人能够通过这个DOM模型来使用该应用程序的功能。这也就是我们通常说的应用程序编程接口:Application Programming Interface,简称API。为了与Windows API这样的编程接口区分开来,我们引入一个专有名词,叫“二次开发接口”。“二次开发”取意于“在现有应用程序基础上进行再开发”。其实如果你愿意把操作系统当作一个更大的应用程序的话,二次开发接口和Windows API并没有什么很大的本质上的差异(尽管我们知道Windows API并不是以COM组件方式提供的)。

理解了自动化(Automation),OA(办公自动化,Office Automation)就比较好解释,无非是应用程序特指办公软件而已。而OA是指办公(包括公文流转)系统的自动化。

在应用程序提供了编程接口(API)的前提下,典型情况下,我们有两种办法来使用这些API。方法一是把应用程序当作一个Server,通过API 对外提供服务。在此情形下,应用程序只是作为一个EXE COM Server的服务程序而已。只要我们理解进程间的LPC或者RPC调用是怎么回事,那么一切就非常Easy。方法二是实现一个应用程序插件 (Addin)。这种方法更有意思一些。首先,这是一种进程内的调用,效率非常好。其次,这是一种双向的通讯,应用程序通过它提供的插件机制感知到插件的 存在,并且将插件加载上来;插件则是在获得活动权后,通过应用程序的API完成特定的功能。最后,也是最重要的,插件与应用程序融为一体,实际上是扩展了 应用程序的能力,使得应用程序变得更为强大。

插件(Addins)的启动过程大体如下:

  1. 应用程序启动。通过注册表(或者存放于其他任何地方)获得插件列表。插件一般以 COM 组件形式提供,故此只要有一个插件的 CLSID 或者 ProgID 的列表就可以了。另外,插件的功能可以千差万别,但是他们需要统一实现一个接口,例如 _IDTExtensibility2 或者类似的东西。这个接口在下面的第二步就用到了。
  2. 遍历插件列表,创建并初始化各插件。关键是初始化。当然应用程序并不知道插件想做什么,它只是取得 _IDTExtensibility2(或者类似接口),调用其中的初始化函数(如 OnConnection)。
  3. 插件获得了初始化机会。注意,在初始化的时候,应用程序把自己的DOM模型的根接口(我们通常称为Application)传入。在 _IDTExtensibility2 中, 根接口被定义为 IDispatch 类型,即 IDispatch* Application。但是实际上可以更通用,如IUnknown* Application。有了这个 Application 指针,插件就可以为所欲为,做它想做的事情,调用它想要调用的任何API。

从插件(Addins)展开来讲,可以讲非常多的内容。然而这不是本文的意图。所以关于这方面的内容,我们只能留待以后有机会继续这个话题。不过我 还是忍不住把话题起个开头:由于插件(Addin)机制使得应用程序结构显得更为灵活,所以,越来越多的软件架构,追求一种超轻量的内核(也就是我们说的 应用程序,之所以称为内核,是因为它是组织一切的核心),并把更多的功能通过插件(Addin)方式提供。超轻量的内核意味着需要解决一个额外的关键点: 就是插件(Addin)不只是扩展应用程序的功能,也同时扩展了应用程序的API,这些API与原有内核的API无缝地结合在一起,从而使得整个系统可以 滚雪球一样越滚越大。

2008年8月29日星期五

续上一篇---UltraEdit 对UTF-8文件的自动处理

长期的疑问,太过信赖ultraedit。。。
http://www.aiview.com/2007/02/ultraedit_auto_detect_utf-8_file.html

关于Unicode 编码,这里有篇文章 可以参考。Unicode是几种多字节编码格式的统称,其中使用广泛的有UTF-8与UTF-16,而通常人们说Unicode时,实际是在指UTF-16编码,UltraEdit 就是这样,为了避免混淆,下面都按照标准引用名字。

使用UltraEdit 打开一个UTF-8 编码的文件,然后按ctrl+h 进入16进制模式查看文件内码,你会发现文件已经被转换成UTF-16 编码,并添加了UTF-16 little endian 的BOM :FF FE,UltraEdit 状态栏文件的尺寸也增加了不少。其实大可不必担心,可以回到正常模式继续编辑并保存,保存后的文件并没有改变编码格式,只是在编辑时使用UTF-16格式而已。

因此,如果通过UltraEdit打开文件查看BOM 来确定文件格式,并不是安全的。UltraEdit 下方状态栏则真实的显示了当前打开文件的实际编码格式,而不是当前编辑的编码格式。 对于一个普通Ascii 格式的文件,它显示为DOS 或者UNIX,对于一个包含有UTF-8编码字符的文件,它显示为U8-DOS 或者U8-UNIX,对于UTF-16编码的文件,它显示为U-DOS 或者U-UNIX。

我们知道,UTF-8 对于Ascii 字符的编码与原有的Ascii 编码一致,因此假如我们删除了一个UTF-8 DOS文件中所有Ascii 以外的字符,保存后再打开,UltraEdit 将显示为DOS(Ascii)。

如果我们不希望UltraEdit 在打开UTF-8 文件时自动转为UTF-16 格式编辑,我们可以修改配置。如下图,确保“自动检测 UTF-8文件”不被选中。

UltraEdit configuration

需要注意的是,如果取消了这个选项,UltraEdit打开包含UTF-8编码的文件会产生乱码。

UltraEdit 在File-Convertions 菜单中提供了多种编码格式之间的转换,这将影响到保存的文件编码,转换后,在状态栏也能看到相应变化。在有些选项后标明有(Unicode Editing) 或者(ASCII Editing),这指定了编辑时显示用的编码,并不影响保存文件所用的编码,要区分开。

工具WinHex 可以用来查看文件16进制内码。

字符编码笔记:ASCII,Unicode和UTF-8

今天中午,我突然想搞清楚UnicodeUTF-8之间的关系,于是就开始在网上查资料。

字符编码笔记:ASCII,UnicodeUTF-8


今天中午,我突然想搞清楚UnicodeUTF-8之间的关系,于是就开始在网上查资料。

结果,这个问题比我想象的复杂,从午饭后一直看到晚上9点,才算初步搞清楚。

下面就是我的笔记,主要用来整理自己的思路。但是,我尽量试图写得通俗易懂,希望能对其他朋友有用。毕竟,字符编码是计算机技术的基石,想要熟练使用计算机,就必须懂得一点字符编码的知识。

1. ASCII码

我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出 256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从 0000000到11111111。

上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。

ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

2、非ASCII编码

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。 于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使 用的编码体系,可以表示最多256个符号。

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码 中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0—127表示的符号是一样的,不一样的只是128—255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。 比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256x256=65536个符号。

中文编码的问题需要专文讨论,这篇笔记不涉及。这里只指出,虽然都是用多个字节表示一个符号,但是GB类的汉字编码与后文的UnicodeUTF-8是毫无关系的。

3.Unicode

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。

Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字“严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表

4. Unicode的问题

需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

比如,汉字“严”的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:1)出现了unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示unicode。2)unicode在很长一段时间内无法推广,直到互联网的出现。

5.UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

下面,还是以汉字“严”为例,演示如何实现UTF-8编码。

已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

6. UnicodeUTF-8之间的转换

通过上一节的例子,可以看到“严”的Unicode码是4E25,UTF-8编码是E4B8A5,两者是不一样的。它们之间的转换可以通过程序实现。

在Windows平台下,有一个最简单的转化方法,就是使用内置的记事本小程序Notepad.exe。打开文件后,点击“文件”菜单中的“另存为”命令,会跳出一个对话框,在最底部有一个“编码”的下拉条。

bg2007102801.jpg

里面有四个选项:ANSI,UnicodeUnicode big endian 和 UTF-8

1)ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。

2)Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。

3)Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。

4)UTF-8编码,也就是上一节谈到的编码方法。

选择完”编码方式“后,点击”保存“按钮,文件的编码方式就立刻转换好了。

7. Little endian和Big endian

上一节已经提到,Unicode码可以采用UCS-2格式直接存储。以汉字”严“为例,Unicode码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big- Endian)敲开还是从小头(Little-Endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

因此,第一个字节在前,就是”大头方式“(Big endian),第二个字节在前就是”小头方式“(Little endian)。

那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

8. 实例

下面,举一个实例。

打开”记事本“程序Notepad.exe,新建一个文本文件,内容就是一个”严“字,依次采用ANSI,UnicodeUnicode big endian 和 UTF-8编码方式保存。

然后,用文本编辑软件UltraEdit中的”十六进制功能“,观察该文件的内部编码方式。

1)ANSI:文件的编码就是两个字节“D1 CF”,这正是“严”的GB2312编码,这也暗示GB2312是采用大头方式存储的。

2)Unicode:编码是四个字节“FF FE 25 4E”,其中“FF FE”表明是小头方式存储,真正的编码是4E25。

3)Unicode big endian:编码是四个字节“FE FF 4E 25”,其中“FE FF”表明是大头方式存储。

4)UTF-8:编码是六个字节“EF BB BF E4 B8 A5”,前三个字节“EF BB BF”表示这是UTF-8编码,后三个“E4B8A5”就是“严”的具体编码,它的存储顺序与编码顺序是一致的。

9. 延伸阅读

* The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets(关于字符集的最基本知识)

* 谈谈Unicode编码

* RFC3629:UTF-8, a transformation format of ISO 10646(如果实现UTF-8的规定)

(完)

相关内容

随机文章

  • 2006.05.15: 《日瓦戈医生》的结尾(Doctor Zhivago)
    晚上,我躺在床上看书,突然读到这样一段:“至今我还记得大卫·里恩的电影《日瓦戈医生》结尾。医生说日瓦戈的心脏已经脆若薄纸。有一天他在莫斯科,坐在 巴士上,车过街角,看到一个年轻女人在路边走,以为那是心爱的拉拉。他挣扎着下车。病犯了,气喘不过来,他松开领带,跌跌撞撞的走到人行道上,只走了两 步,载倒在地上,就这样死了。死亡追逐爱情,爱情正是我们以死相求的东西。”
  • 2007.04.26: 2007年普利策奖回顾之二:突发新闻奖
    突发新闻奖(BREAKING NEWS REPORTING) 2006年11月17日,星期五 35岁的James Kim带着妻子和两个女儿——一个4岁,另一个7个月——离开旧金山,开车前往西雅图的叔叔家,一起过感恩节假期。他是一个网站编辑。

功能链接

广告(点击支持我)



评论

Stark 说:

很有意思的内容
讲解得通俗易懂,非常感谢您用较长的时间学习,并用精简的语言概括

flyisland 说:

本人是计算机从业人员,对文中提到的知识也都基本了解,但是像阮兄这样,花了半天时间就弄清楚来龙去脉,同时讲述的如此清楚,实在佩服。

本帖有pmp嫌疑,但实在是不能不p啊 :)。我想,动手写过技术文章的人都会同意我的。

只如初见 说:

是啊,我这个超级菜鸟都看明白了,阮兄对技术的理解和说明能力叫人佩服,谢谢分享。

姬着 说:

文章里说:UCS-2编码方式,即直接用两个字节存入字符的Unicode码。

那USC-2编码方式如何实现超过两个字节的符号的存储?谢谢

大徐 说:

对了解字符编码很有帮助,谢谢!

Ruan YiFeng 说:

引用只如初见的发言:
是啊,我这个超级菜鸟都看明白了,阮兄对技术的理解和说明能力叫人佩服,谢谢分享。

“延伸阅读”中第一个链接,才是真正的通俗易懂,我只是向他学习而已。

Ruan YiFeng 说:

引用姬着的发言:
文章里说:UCS-2编码方式,即直接用两个字节存入字符的Unicode码。 那USC-2编码方式如何实现超过两个字节的符号的存储?谢谢

USC-2只能用存储两个字节的Unicode,超过这一范围的符号,它不能表示。

Annis 说:


我是Annis,想邀请您参加拼搏到底FeedSky博客挑战赛,
这是一个很好的宣传、展示自己的机会,
有兴趣您可以自己到相关网站了解具体参赛细节。
http://www.feedsky.com/challenge/?u=141270

Bill 说:

PS:本文只是主要介绍了UTF-8编码,下面这篇文章对于GB码与Big5有更详细的介绍。

汉字编码中现在主要用到的有三类,包括GBK,GB2312和Big5。

1、GB2312又称国标码,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括 其他的符号、字母、日文假名等,共7445个图形字符,其中汉字占6763个。我们平时说6768个汉字,实际上里边有5个编码为空白,所以总共有 6763个汉字。

GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。 GB2312中汉字的编码范围为,第一字节0xB0-0xF7(对应十进制为176-247),第二个字节0xA0-0xFE(对应十进制为160- 254)。

GB2312将代码表分为94个区,对应第一字节(0xa1-0xfe);每个区94个位(0xa1-0xfe),对应第二字节,两个字节的值分别为区号 值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区(0xb0-0xf7),10-15区、88-94区 是有待进一步标准化的空白区。


2、Big5又称大五码,主要为香港与台湾使用,即是一个繁体字编码。每个汉字由两个字节构成,第一个字节的范围从0X81-0XFE(即129- 255),共126种。第二个字节的范围不连续,分别为0X40-0X7E(即64-126),0XA1-0XFE(即161-254),共157种。


3、GBK是GB2312的扩展,是向上兼容的,因此GB2312中的汉字的编码与GBK中汉字的相同。另外,GBK中还包含繁体字的编码,它与Big5 编码之间的关系我还没有弄明白,好像是不一致的。GBK中每个汉字仍然包含两个字节,第一个字节的范围是0x81-0xFE(即129-254),第二个 字节的范围是0x40-0xFE(即64-254)。GBK中有码位23940个,包含汉字21003个。

Bill再推荐一个网站 专门介绍汉字与汉字计算机化的 汉典 http://www.zdic.net/

简单 说:

http://www.zdic.net/


很强的网站,收藏

Ruan YiFeng 说:

引用Bill的发言:
本文只是主要介绍了UTF-8编码,下面这篇文章对于GB码与Big5有更详细的介绍。

这篇网志中有两个地方需要补充一下,我忘了在原文中提到。

1.

国际标准化组织通过了一套ISO-8859-1的编码,规定了单字节256个符号的编码方式。目前,这是8位编码的国际标准。

2.

Unicode编码中表示字节排列顺序的那个文件头,叫做BOM(byte-order mark),FFFE和FEFF就是不同的BOM。

UTF-8文件的BOM是“EF BB BF”,但是UTF-8的字节顺序是不变的,因此这个文件头实际上不起作用。有一些编程语言是ISO-8859-1编码,所以如果用UTF-8针对这些语言编程序,就必须去掉BOM,即保存成“UTF-8—无BOM”的格式才可以,PHP语言就是这样。

请教 说:

我怎么用 notepad 保存成 UTF-8
用 UltraEdit 看 还是 FF FE 25 4E啊???

请教 说:

引用请教的发言:
我怎么用 notepad 保存成 UTF-8 后 用 UltraEdit 看 还是 FF FE 25 4E啊???
哦 知道了。 是UltraEdit 默认会以 UTF-16的方式打开UTF-8编码的文件, 要设置或者用Hex Workshop打开就可以看到楼主所说的效果。

Cloudream 说:

(点击支持我)

这些字符是违反adsense规定的……

jackywdx 说:

这么精彩的讲解,实在不得不向作者致敬!
内容讲解得非常详细但又通俗易懂,谢谢了~~

jinwangen 说:

非常感谢

LMN 说:

非常感谢,值得一看

网友 说:

标题“6. UnicodeUTF-8之间的转换”不严谨。

Unicode是一种字符集,概念比较抽象,你已经提到,它存储的时候必须用适当的编码方式。

你的标题的意思,实际上是UTF-16和UTF-8之间的转换。

至于windows notepad保存对话框的编码方式列表中列出“Unicode”这一个名字,实际上是一个通俗的称呼(来自windows NT的早期版本的习惯,一直沿用),指UTF-16,而不是严格的称呼。希望你行文不要受这个影响。

Ruan YiFeng 说:

引用网友的发言:

标题“6. UnicodeUTF-8之间的转换”不严谨。

Unicode是一种字符集,概念比较抽象,你已经提到,它存储的时候必须用适当的编码方式。

你的标题的意思,实际上是UTF-16和UTF-8之间的转换。

UTF-16不等于unicode啊,不能混为一谈。

Ivan WONG 说:

嗯,看完了長不少知識.

Michael Zheng 说:

我只能这么说,看了那么多的对字符集的解释

这个绝对是最通俗易懂并且还解决了常见疑问的最好的文章 :)

收藏

wxs8088 说:

很好的一编文章

人跟人的差距咋就这么大呢 说:

好文章!收藏了!

楼主何不把ansi编码方式也说说!
让俺这样的小学新生借楼主的理解能力再学习一把.

学习了 说:

学习了

水中鱼 说:

引用Ruan YiFeng的发言:

UTF-16不等于unicode啊,不能混为一谈。


UTF-16扩充了Unicode,包括了一些稀有字符,想我们国家的满文,藏文等等,两者基本上等价

heroboy 说:

其实我认为,编码其实有2个意思。1.一个是把字符和数字对应起来(比如unicode和GBXXXX等)。2.还有就是相应在数字在计算机中的表示,也就是和字节序列对应起来(比如utf8,mbcs等)。
我有个问题,windows下的mbcs编码(2)用的编码(1)是不是GB系列的编码(1),而unicode编码(2)用的是unicode编码(1)

Demo 说:

拜读。。。受益匪浅。。长见识了 。。顶楼主

2008年08月15日 01:56 | | 引用