PHP网页导出Word文档的方法(MHT)

注意:本文引用地址: http://www.cnitblog.com/CoffeeCat/archive/2008/08/07/47753.html

原理

    一般,有2种方法可以导出doc文档,一种是使用com,并且作为php的一个扩展库安装到服务器上,然后创建一个com,调用它的方法。安装过office的服务器可以调用一个叫word.application的com,可以生成word文档,不过这种方式我不推荐,因为执行效率比较低(我测试了一下,在执行代码的时候,服务器会真的去打开一个word客户端)。理想的com应该是没有界面的,在后台进行数据转换,这样效果会比较好,但是这些扩展一般需要收费。
    第2种方法,就是用PHP将我们的doc文档内容直接写入一个后缀为doc的文件中即可。使用这种方法不需要依赖第三方扩展,而且执行效率较高。
    word本身的功能还是很强大的,它可以打开html格式的文件,并且能够保留格式,即使后缀为doc,它也能识别正常打开。这就为我们提供了方便。但是有一个问题,html格式的文件中的图片只有一个地址,真正的图片是保存在其他地方的,也就是说,如果将HTML格式写入doc中,那么doc中将不能包含图片。那我们如何创建包含图片的doc文档呢?我们可以使用和html很接近的mht格式。
    mht格式和html很类似,只不过在mht格式中,外部链接进来的文件,比如图片、Javascript、CSS会被base64进行编码存储。因此,单个mht文件就可以保存一个网页中的所有资源,当然,相比html,它的尺寸也会比较大。
    mht格式能被word识别吗?我将一个网页保存成mht,然后修改后缀名为doc,再用word打开,OK,word也可以识别mht文件,并且可以显示图片。
    好了,既然doc可以识别mht,下面就是考虑如何将图片放入mht了。由于html代码中的图片的地址都是写在img标签的src属性中,因此,只要提取html代码中的src属性值,就可以获得图片地址。当然,有可能您获取到的是相对路径,没关系,加上URL的前缀,改成绝对路径就可以了。有了图片地址,我们就可以通过file_get_content函数获取到图片文件的具体内容,然后调用base64_encode函数将文件内容编码成base64编码,最后插入到mht文件的合适位置即可。
    最后,我们有两种方法将文件发送给客户端,一种是先在服务器端生成一个doc文档,然后将这个doc文档的地址记录下来,最后,通过header("location:xx.doc");就可以让客户端下载这个doc。还有一种是直接发送html请求,修改HTML协议的header部分,将它的content-type设置为application/doc,将content-disposition设置为attachment,后面跟上文件名,发送完html协议以后,直接将文件内容发送给客户端,也可以让客户端下载到这个doc文档。

 

实现

    通过以上的原理介绍,相信大家应该对实现的过程有个初步的了解了,下面我给出一个导出函数,这个函数可以将HTML代码导出成一个mht文档,参数有3个,其中后2个为可选参数
    content:要转换的HTML代码
    absolutePath: 如果HTML代码中的图片地址都是相对路径,那么这个参数就是HTML代码中缺少的绝对路径。
    isEraseLink:是否去掉HTML代码中的超链接

    返回值为mht的文件内容,您可以通过file_put_content将它保存成后缀名为doc的文件

    这个函数的主要功能其实就是分析HTML代码中的所有图片地址,并且依次下载下来。获取到了图片的内容以后,调用MhtFileMaker类,将图片添加到mht文件中。具体的添加细节,封装在MhtFileMaker类中了。

 

/* *
 * 根据HTML代码获取word文档内容
 * 创建一个本质为mht的文档,该函数会分析文件内容并从远程下载页面中的图片资源
 * 该函数依赖于类MhtFileMaker
 * 该函数会分析img标签,提取src的属性值。但是,src的属性值必须被引号包围,否则不能提取
 * 
 * @param string $content HTML内容
 * @param string $absolutePath 网页的绝对路径。如果HTML内容里的图片路径为相对路径,那么就需要填写这个参数,来让该函数自动填补成绝对路径。这个参数最后需要以/结束
 * @param bool $isEraseLink 是否去掉HTML内容中的链接
 
*/
function  getWordDocument(  $content   ,   $absolutePath   =   ""   ,   $isEraseLink   =   true  )
{
    
$mht   =   new  MhtFileMaker();
    
if  ( $isEraseLink )
        
$content   =   preg_replace ( ' /<a\s*.*?\s*>(\s*.*?\s*)<\/a>/i '   ,   ' $1 '   ,   $content );    // 去掉链接

    
$images   =   array ();
    
$files   =   array ();
    
$matches   =   array ();
    
// 这个算法要求src后的属性值必须使用引号括起来
     if  (  preg_match_all ( ' /<img[.\n]*?src\s*?=\s*?[\"\ ' ]( .*? )[\ " \'](.*?)\/>/i',$content ,$matches ) )
    {
        $arrPath = $matches[1];
        for ( $i=0;$i<count($arrPath);$i++)
        {
            $path = $arrPath[$i];
            $imgPath = trim( $path );
            if ( $imgPath != 
""  )
            {
                $files[] = $imgPath;
                if( substr($imgPath,0,7) == 'http://')
                {
                    //绝对链接,不加前缀
                }
                else
                {
                    $imgPath = $absolutePath.$imgPath;
                }
                $images[] = $imgPath;
            }
        }
    }
    $mht->AddContents(
" tmp . html " ,$mht->GetMimeType( " tmp . html " ),$content);
    
    for ( $i=0;$i<count($images);$i++)
    {
        $image = $images[$i];
        if ( @fopen($image , 'r') )
        {
            $imgcontent = @file_get_contents( $image );
            if ( $content )
                $mht->AddContents($files[$i],$mht->GetMimeType($image),$imgcontent);
        }
        else
        {
            echo 
" file : " .$image. "  not exist !< br  /> " ;
        }
    }
    
    return $mht->GetFile();
}

使用方法:
 

$fileContent   =  getWordDocument( $content , " http://www.yoursite.com/Music/etc/ " );
$fp   =   fopen ( " test.doc " ,   ' w ' );
fwrite ( $fp ,   $fileContent );
fclose ( $fp );

其中,$content变量应该是HTML源代码,后面的链接应该是能填补HTML代码中图片相对路径的URL地址

注意,在使用这个函数之前,您需要先包含类MhtFileMaker,这个类可以帮助我们生成Mht文档。

 

<? php
/* **********************************************************************
Class:        Mht File Maker
Version:      1.2 beta
Date:         02/11/2007
Author:       Wudi <wudicgi@yahoo.de>
Description:  The class can make .mht file.
**********************************************************************
*/

class  MhtFileMaker{
    
var   $config   =   array ();
    
var   $headers   =   array ();
    
var   $headers_exists   =   array ();
    
var   $files   =   array ();
    
var   $boundary ;
    
var   $dir_base ;
    
var   $page_first ;

     function  MhtFile( $config   =   array ()){

    }

     function  SetHeader( $header ){
        
$this -> headers[]  =   $header ;
        
$key   =   strtolower ( substr ( $header ,   0 ,   strpos ( $header ,   ' : ' )));
        
$this -> headers_exists[ $key =   TRUE ;
    }

     function  SetFrom( $from ){
        
$this -> SetHeader( " From: $from " );
    }

     function  SetSubject( $subject ){
        
$this -> SetHeader( " Subject: $subject " );
    }

     function  SetDate( $date   =   NULL ,   $istimestamp   =   FALSE ){
        
if  ( $date   ==   NULL ) {
            
$date   =   time ();
        }
        
if  ( $istimestamp   ==   TRUE ) {
            
$date   =   date ( ' D, d M Y H:i:s O ' ,   $date );
        }
        
$this -> SetHeader( " Date: $date " );
    }

     function  SetBoundary( $boundary   =   NULL ){
        
if  ( $boundary   ==   NULL ) {
            
$this -> boundary  =   ' -- '   .   strtoupper ( md5 ( mt_rand ()))  .   ' _MULTIPART_MIXED ' ;
        } 
else  {
            
$this -> boundary  =   $boundary ;
        }
    }

     function  SetBaseDir( $dir ){
        
$this -> dir_base  =   str_replace ( " \\ " ,   " / " ,   realpath ( $dir ));
    }

     function  SetFirstPage( $filename ){
        
$this -> page_first  =   str_replace ( " \\ " ,   " / " ,   realpath ( " {$this->dir_base}/$filename " ));
    }

     function  AutoAddFiles(){
        
if  ( ! isset ( $this -> page_first)) {
            
exit  ( ' Not set the first page. ' );
        }
        
$filepath   =   str_replace ( $this -> dir_base ,   '' ,   $this -> page_first);
        
$filepath   =   ' http://mhtfile '   .   $filepath ;
        
$this -> AddFile( $this -> page_first ,   $filepath ,   NULL );
        
$this -> AddDir( $this -> dir_base);
    }

     function  AddDir( $dir ){
        
$handle_dir   =   opendir ( $dir );
        
while  ( $filename   =   readdir ( $handle_dir )) {
            
if  (( $filename != ' . ' &&  ( $filename != ' .. ' &&  ( " $dir/$filename " != $this -> page_first)) {
                
if  ( is_dir ( " $dir/$filename " )) {
                    
$this -> AddDir( " $dir/$filename " );
                } 
elseif  ( is_file ( " $dir/$filename " )) {
                    
$filepath   =   str_replace ( $this -> dir_base ,   '' ,   " $dir/$filename " );
                    
$filepath   =   ' http://mhtfile '   .   $filepath ;
                    
$this -> AddFile( " $dir/$filename " ,   $filepath ,   NULL );
                }
            }
        }
        
closedir ( $handle_dir );
    }

     function  AddFile( $filename ,   $filepath   =   NULL ,   $encoding   =   NULL ){
        
if  ( $filepath   ==   NULL ) {
            
$filepath   =   $filename ;
        }
        
$mimetype   =   $this -> GetMimeType( $filename );
        
$filecont   =   file_get_contents ( $filename );
        
$this -> AddContents( $filepath ,   $mimetype ,   $filecont ,   $encoding );
    }

     function  AddContents( $filepath ,   $mimetype ,   $filecont ,   $encoding   =   NULL ){
        
if  ( $encoding   ==   NULL ) {
            
$filecont   =   chunk_split ( base64_encode ( $filecont ) ,   76 );
            
$encoding   =   ' base64 ' ;
        }
        
$this -> files[]  =   array ( ' filepath '   =>   $filepath ,
                               
' mimetype '   =>   $mimetype ,
                               
' filecont '   =>   $filecont ,
                               
' encoding '   =>   $encoding );
    }

     function  CheckHeaders(){
        
if  ( ! array_key_exists ( ' date ' ,   $this -> headers_exists)) {
            
$this -> SetDate( NULL ,   TRUE );
        }
        
if  ( $this -> boundary  ==   NULL ) {
            
$this -> SetBoundary();
        }
    }

     function  CheckFiles(){
        
if  ( count ( $this -> files)  ==   0 ) {
            
return   FALSE ;
        } 
else  {
            
return   TRUE ;
        }
    }

     function  GetFile(){
        
$this -> CheckHeaders();
        
if  ( ! $this -> CheckFiles()) {
            
exit  ( ' No file was added. ' );
        }
        
$contents   =   implode ( " \r\n " ,   $this -> headers);
        
$contents   .=   " \r\n " ;
        
$contents   .=   " MIME-Version: 1.0\r\n " ;
        
$contents   .=   " Content-Type: multipart/related;\r\n " ;
        
$contents   .=   " \tboundary=\ " { $this -> boundary}\ " ;\r\n " ;
        
$contents   .=   " \ttype=\ ""  . $this->files[0]['mimetype'] .  " \ " \r\n " ;
        
$contents   .=   " X-MimeOLE: Produced By Mht File Maker v1.0 beta\r\n " ;
        
$contents   .=   " \r\n " ;
        
$contents   .=   " This is a multi-part message in MIME format.\r\n " ;
        
$contents   .=   " \r\n " ;
        
foreach  ( $this -> files  as   $file ) {
            
$contents   .=   " --{$this->boundary}\r\n " ;
            
$contents   .=   " Content-Type: $file[mimetype]\r\n " ;
            
$contents   .=   " Content-Transfer-Encoding: $file[encoding]\r\n " ;
            
$contents   .=   " Content-Location: $file[filepath]\r\n " ;
            
$contents   .=   " \r\n " ;
            
$contents   .=   $file [ ' filecont ' ];
            
$contents   .=   " \r\n " ;
        }
        
$contents   .=   " --{$this->boundary}--\r\n " ;
        
return   $contents ;
    }

     function  MakeFile( $filename ){
        
$contents   =   $this -> GetFile();
        
$fp   =   fopen ( $filename ,   ' w ' );
        
fwrite ( $fp ,   $contents );
        
fclose ( $fp );
    }

     function  GetMimeType( $filename ){
        
$pathinfo   =   pathinfo ( $filename );
        
switch  ( $pathinfo [ ' extension ' ]) {
            
case   ' htm ' :   $mimetype   =   ' text/html ' break ;
            
case   ' html ' :   $mimetype   =   ' text/html ' break ;
            
case   ' txt ' :   $mimetype   =   ' text/plain ' break ;
            
case   ' cgi ' :   $mimetype   =   ' text/plain ' break ;
            
case   ' php ' :   $mimetype   =   ' text/plain ' break ;
            
case   ' css ' :   $mimetype   =   ' text/css ' break ;
            
case   ' jpg ' :   $mimetype   =   ' image/jpeg ' break ;
            
case   ' jpeg ' :   $mimetype   =   ' image/jpeg ' break ;
            
case   ' jpe ' :   $mimetype   =   ' image/jpeg ' break ;
            
case   ' gif ' :   $mimetype   =   ' image/gif ' break ;
            
case   ' png ' :   $mimetype   =   ' image/png ' break ;
            
default :   $mimetype   =   ' application/octet-stream ' break ;
        }
        
return   $mimetype ;
    }
}
?>

   

发表在 article | 标签为 | PHP网页导出Word文档的方法(MHT)已关闭评论

AS2----声音(Sound类)语句

Sound 类使您可以在影片中添加声音,并控制这些声音。
    在调用 Sound 类的方法之前,您必须使用构造函数 new Sound 创建 Sound 对象。(详见九
    方法:对象名称 = new Sound();
    实例:mysound = new Sound();
    一、添加声音

    1、从库中添加声音

    用法:mysound.attachSound("idName")
    参数:idName 库中导出声音的标识符。该标识符位于“链接属性”对话框
    注解:将库中链接标识符为idName 的声音,附加到对象mysound中。
          打开“链接属性”对话框方法:指向库中的声音元件-右键-选






























“链接”--“为
ActionScript 导出”左边方框打勾-输入标识符-确定。
    2、从外部添加声音

    用法:mysound.loadSound("url", isStreaming)
    参数:url MP3 声音文件的网址。
          isStreaming 一个布尔值,指示声音是声音流 (true) 还是事件声音 (false)
    注解:网址为url的mp3 以声音流或事件声音方式下载附加到对象mysound中。
          事件声音在完全加载后才能播放。
          声音流在下载的同时播放。当接收的数据足以启动解压缩程序时,播放开始。
    实例:mysound.loadSound( "http://www.gz-travel.net/music/mp3/爱心(日语版).mp3",










































true);
    二、播放声音

    用法:mysound.start([secondOffset, loop])
    参数:secondOffset 一个可选参数,用于从某个特定点开始播放声音。例如,如果您有一个









30 秒的声音,而您希望该声音从中间开始播放,可将 secondOffset 参数指定为 15。
          loop 一个可选参数,用于指定声音连续播放的次数。
    注解:如果未指定参数,则从开头开始播放最近附加的声音;或者从参数 secondOffset 指定












的声音点处开始播放。
    实例:(1)mysound.start();(2)mysound.start(15);
    三、停止声音播放

    用法:mysound.stop(["idName"])
    参数:idName 一个可选参数,用于指定要停止播放的某个特定声音。idName 参数必须置于引












号 (" ") 之中。
    注解:如果未指定参数,则停止当前播放的所有声音,否则只停止在 idName 参数中指定的声



音。
    实例:(1)mysound.stop();(2)mysound.stop("mp3-02");
    四、声音音量控制

    用法:mysound.setVolume(volume)
    参数:volume 一个从 0 到 100 之间的数字,表示声音级别。100 为最大音量,而 0 为没有












音量。默认设置为 100。
    实例:mysound.setVolume(50);音量设置为 50%。
    五、声音的左右声道控制

    用法:mysound.setPan(pan);
    参数:pan 一个整数,指定声音的左右均衡。有效值的范围为 -100 到 100,其中 -100 表示












仅使用左声道,100 表示仅使用右声道,而 0 表示在两个声道间平均地均衡声音。
    注解:确定声音在左右声道(扬声器)中是如何播放的。对于单声道声音,pan 确定声音通过



哪个扬声器(左或右)进行播放。
    实例:mysound.setPan(-100);关闭右声道中的声音
    六、读取声音的长度

    用法:mysound.duration
    注解:属性(只读);声音的持续时间,以毫秒为单位。
    实例:ms=mysound.duration/1000;ms的值是声音长度为xx秒。
    七、读取已播放声音的长度

    用法:mysound.position
    注解:属性(只读);声音已播放的毫秒数。如果声音是循环的,则在每次循环开始时,位置
























将被重置为 0。
    实例:bfms=mysound.position/1000;bfms的值是声音已播放的长度为xx秒。
    八、其他声音(Sound类)语句

    Sound.getBytesLoaded() 返回为指定声音加载的字节数。
    Sound.getBytesTotal() 以字节为单位返回声音的大小。
    Sound.getPan() 返回上一个 setPan() 调用的值。
    Sound.getTransform() 返回上一个 setTransform() 调用的值。
    Sound.getVolume() 返回上一个 setVolume() 调用的值。
    Sound.setTransform() 设置要在每个扬声器中播放的每个声道(左声道和右声道)的音量。
    Sound.ID3 提供对作为 MP3 文件一部分的元数据的访问。
    Sound.onID3 每次有新的 ID3 数据可用时调用。
    Sound.onLoad 加载声音时调用。
    Sound.onSoundComplete 声音停止播放时调用。
    九、Sound 类的构造函数

    用法:new Sound([target])
    参数:target Sound 对象操作的影片剪辑实例。此参数是可选的。
    说明:构造函数;为指定的影片剪辑创建新的 Sound 对象。如果没有指定目标实例,则
















































Sound 对象控制影片中的所有声音。   
    下面的示例当按下鼠标左键时创建一个 Sound 对象 my_sound,并从库中为其附加具有标识符






L7 的声音。它还调用setVolume() 和 setPan() 来控制 L7 声音。
    onClipEvent(mouseDown) {
    // 创建一个声音对象
      my_sound = new Sound(this);
    // 从库中附加声音
      my_sound.attachSound("L7");
    //将音量设置为 50%
      my_sound.setVolume(50);
    //关闭右声道中的声音
      my_sound.setPan(-100);
    //从声音的第 30 秒开始播放并播放 5 遍
      my_sound.start(30, 5);
    }














































 





































































































































































































































































发表在 article | 标签为 | 65条评论

C#3.0基于Speech.Synthesis调整语音朗读语调范例

using System;
using System.Speech.Synthesis;
namespace Speech_Synthesis
{
    public partial class Window1 : System.Windows.Window
    {
        public Window1()
        {
            InitializeComponent();

            SpeechSynthesizer synthesizer = new SpeechSynthesizer();
            PromptBuilder promptBuilder = new PromptBuilder();

            promptBuilder.AppendTextWithHint("尹成", SayAs.SpellOut);
            promptBuilder.AppendText("尹成大哥毕业于山东大学.");

         
            promptBuilder.AppendBreak(new TimeSpan(0, 0, 2));
           
            promptBuilder.AppendText("尹成大哥是谁");
            promptBuilder.AppendTextWithHint(DateTime.Now.ToString("hh:mm"), SayAs.Time);
           
            // Pause for 2 seconds
            promptBuilder.AppendBreak(new TimeSpan(0, 0, 2));
           
            promptBuilder.AppendText("尹成大哥硕士毕业于中科院?");
           
            promptBuilder.StartVoice("Microsoft Sam");
            promptBuilder.AppendTextWithHint("queue", SayAs.SpellOut);
            promptBuilder.EndVoice();
           
            promptBuilder.AppendText("Do it faster!");
           
            promptBuilder.StartVoice("Microsoft Sam");
            promptBuilder.StartStyle(new PromptStyle(PromptRate.ExtraFast));
            promptBuilder.AppendTextWithHint("queue", SayAs.SpellOut);
            promptBuilder.EndStyle();
            promptBuilder.EndVoice();

            // Speak all the content in the PromptBuilder
            synthesizer.SpeakAsync(promptBuilder);
        }
    }
}

--------------------------------------------------------------

语音合成

1、使用语音合成

        speechsynthesizer
synth = new
speechsynthesizer
();

 

            //

获取本机上所安装的所有的voice的名称

            string
voicestring = ""
;

 

            foreach
(installedvoice
iv in
synth.getinstalledvoices())

            {

                voicestring += iv.voiceinfo.name + ","
;

            }

 

            //

根据voice的name属性确定要使用的voice

            synth.selectvoice("vw lily"
);         

            //

根据文字内容合成语音

            synth.speak(this
.textbox1.text);

            synth.speak("

中华人民共和国湖北省"
);

2
构建ssml

                       

            promptbuilder
myprompt = new
promptbuilder
();

 

            //start the main speaking style

            promptstyle
mainstyle = new
promptstyle
();

            mainstyle.rate = promptrate
.medium;

            mainstyle.volume = promptvolume
.loud;

            myprompt.startstyle(mainstyle);

 

            //alert the listener

            myprompt.appendaudio(new
uri
(

                "file://c:""windows""media""notify.wav"
), "attention!"
);   //appendaudio

功能使 wav 文件与输出结合,

                 //

假如未找到 wav 文件,可以使用一个等效文本文件,即第二个参数

            myprompt.appendtext("here are some important messages."
);

 

            //here's the first important message

            myprompt.appendtextwithpronunciation("winfx"
, "w

?
n
?
f
?
ks"
); //appendtextwithpronunciation

功能答应您指定单词的正确发音

            myprompt.appendtext("is a great platform."
);

 

            //and the second one

            myprompt.appendtextwithhint("asp"
, sayas
.spellout); // appendtextwithhint

功能为缩写词作标记

            //sayas

枚举值举例: sayas.numberordinal sayas.daymonth sayas.spellout sayas.telephone sayas.text sayas.time24等

            myprompt.appendtext(

                "is an acronym for active server pages. whereas an asp is a snake."
);

 

            myprompt.appendbreak();

 

           //let's emphasise how important these messages are

            promptstyle
interimstyle = new
promptstyle
();

            interimstyle.emphasis = promptemphasis
.strong;

            myprompt.startstyle(interimstyle);

            myprompt.appendtext("please remember these two things."
);

            myprompt.endstyle();

 

            //then we can revert to the main speaking style

            myprompt.appendbreak();

            myprompt.appendtext("thank you"
);

 

            myprompt.endstyle();

            //now let's get the synthesizer to render this message

            speechsynthesizer
synth = new
speechsynthesizer
();

            synth.selectvoice("vw lily"
);

            synth.speakasync(myprompt); //

与speak不同的异步方法
 

 

3
将构建的ssml保存在ssml文件中

            using
(streamwriter
promptwriter = new
streamwriter
("c:""prompt.ssml"
))

            {

                promptwriter.write(myprompt.toxml());

            }

4
将构建的语音保存为一个wav文件中

//
若前面使用了speakasync方法,则不能输出为wav文件。

            //

必须等到语音播完后才能输出           

            synth.setoutputtowavefile("c:""message.wav"
);

            synth.speak(myprompt);

            synth.setoutputtonull();

5
根据ssml文件中保存的信息还原为语音

            speechsynthesizer
synth = new
speechsynthesizer
();

            promptbuilder
savedprompt = new
promptbuilder
();

            savedprompt.appendssml("c:""prompt.ssml"
);

            synth.selectvoice("vw lily"
);

            synth.speak(savedprompt);

 

6

通过语音进度事件高光显示正在阅读的文本位置


          
speechsynthesizer
synth = new
speechsynthesizer
();

 
synth.speakprogress += new
eventhandler
<speakprogresseventargs
>(synth_speakprogress);

void
synth_speakprogress(object
sender, speakprogresseventargs
e)

       
{

           
this
.textbox1.hideselection = false
;          


           
this
.textbox1.select(e.characterposition,e.charactercount );

       
}

发表在 article | 标签为 , , , | C#3.0基于Speech.Synthesis调整语音朗读语调范例已关闭评论

IE6 掉字(CSS )

在日常工作中,常遇到IE6多出一行字或一个字的情况,网上大多同仁说是注释问题。经查,不一定是注释才会引起该类问题,个人感觉是因为一些不可显示的元素存在在了具有 float css属性的元素内的问题,只要将这些不可显示的元素移出这个范围一般就会恢复,如: 脚本块,css块,注释块,隐藏表单等。

发表在 mood | 标签为 | IE6 掉字(CSS )已关闭评论

C# Speech 中文发音

我们要想实现中文发音或中文语音识别,必需先安装微软的Speech Application SDK(SASDK),它的最新版本是 SAPI 5.1 他能够识别中、日、英三种语言,你可以在这里下载:http://www.microsoft.com/speech/download/sdk51/,需要安装这两个文件Speech SDK 5.1和5.1 Language Pack,其中5.1 Language Pack可以选择安装支持的语言。  安装好以后,我们就可以开始进行语音程序的开发了。

下面我们设计一个能够朗读中英文混合语言的类:

我们将用单例模式实现该类,类的代码如下,我们将详细解释:

 

public class Speach

{

  private static Speach _Instance = null ;

  private SpeechLib.SpVoiceClass voice =null;

  private Speach()

  {

BuildSpeach() ;

  }

public static Speach instance()

{

  if (_Instance == null)

_Instance = new Speach() ;

return _Instance ;

}

private void SetChinaVoice()

{

  voice.Voice = voice.GetVoices(string.Empty,string.Empty).Item(0) ;

}

private void SetEnglishVoice()

{

  voice.Voice = voice.GetVoices(string.Empty,string.Empty).Item(1) ;

}

private void SpeakChina(string strSpeak)

{

  SetChinaVoice() ;

  Speak(strSpeak) ;

}

private void SpeakEnglishi(string strSpeak)

{

  SetEnglishVoice() ;

  Speak(strSpeak) ;

}

public void AnalyseSpeak(string strSpeak)

{

  int iCbeg = 0 ;

  int iEbeg = 0 ;

  bool IsChina = true ;

  for(int i=0;i<strSpeak.Length;i++)

  {

char chr = strSpeak[i] ;

if (IsChina)

{

  if (chr<=122&&chr>=65)

  {

int iLen = i - iCbeg ;

string strValue = strSpeak.Substring(iCbeg,iLen) ;

SpeakChina(strValue) ;

iEbeg = i ;

IsChina = false ;

  }

}

else

{

  if (chr>122||chr<65)

  {

int iLen = i - iEbeg ;

string strValue = strSpeak.Substring(iEbeg,iLen) ;

this.SpeakEnglishi(strValue) ;

iCbeg = i ;

IsChina = true ;

  }

}

  }//end for

  if (IsChina)

  {

int iLen = strSpeak.Length - iCbeg ;

string strValue = strSpeak.Substring(iCbeg,iLen) ;

SpeakChina(strValue) ;

  }

  else

  {

int iLen = strSpeak.Length - iEbeg ;

string strValue = strSpeak.Substring(iEbeg,iLen) ;

SpeakEnglishi(strValue) ;

  }

}

private void BuildSpeach()

{

  if (voice == null)

voice = new SpVoiceClass() ;

}

public int Volume

{

  get

  {

return voice.Volume ;

  }

  set

  {

voice.SetVolume((ushort)(value)) ;

  }

}

public int Rate

{

  get

  {

return voice.Rate ;

  }

  set

  {

voice.SetRate(value) ;

  }

}

private void Speak(string strSpeack)

{

  try

  {

voice.Speak(strSpeack,SpeechVoiceSpeakFlags.SVSFlagsAsync) ;

  }

  catch(Exception err)

  {

throw(new Exception("发生一个错误:"+err.Message)) ;

  }

}

public void Stop()

{

  voice.Speak(string.Empty,SpeechLib.SpeechVoiceSpeakFlags.SVSFPurgeBeforeSpeak) ;

}

public void Pause()

{

  voice.Pause() ;

}

public void Continue()

{

  voice.Resume() ;

}

}//end class

 

 

 

在 private SpeechLib.SpVoiceClass voice =null;这里,我们定义个一个用来发音的类,并且在第一次调用该类时,对它用BuildSpeach方法进行了初始化。 

我们还定义了两个属性Volume和Rate,能够设置音量和语速。

我们知道,SpVoiceClass 有一个Speak方法,我们发音主要就是给他传递一个字符串,它负责读出该字符串,如下所示。

 

private void Speak(string strSpeack)

{

  try

  {

voice.Speak(strSpeack,SpeechVoiceSpeakFlags.SVSFlagsAsync) ;

  }

  catch(Exception err)

  {

throw(new Exception("发生一个错误:"+err.Message)) ;

  }

}

 

其中SpeechVoiceSpeakFlags.SVSFlagsAsync表示异步发音。

点击查看原图
screen.width-600)this.style.width=screen.width-600;" border=0> 但是,这个方法本身并不知道你给的字符串是什么语言,所以需要我们它这个字符串用什么语言读出。SpVoiceClass 类的Voice 属性就是用来设置语种的,我们可以通过SpVoiceClass 的GetVoices方法得到所有的语种列表,然后在根据参数选择相应的语种,比如设置语种为汉语如下所示:

 

private void SetChinaVoice()

{

  voice.Voice = voice.GetVoices(string.Empty,string.Empty).Item(0) ;

}

0表示是汉用,1234都表示英语,就是口音不同。 

这样,我们就设置了语种,如果结合发音方法,我们就可以设计出一个只发汉语语音的方法

 

private void SpeakChina(string strSpeak)

{

  SetChinaVoice() ;

  Speak(strSpeak) ;

}

只发英语语音的方法也是类似的,上面程序里有。

对于一段中英文混合的语言,我们让程序读出混合语音的方法就是:编程把这段语言的中英文分开,对于中文调用SpeakChina方法,英文调用SpeakEnglishi方法;至于怎样判断一个字符是英文还是中文,我采用的是判断asc码的方法,具体的类方法是通过AnalyseSpeak实现的。 

这样,对于一段中英文混合文字,我们只需把它作为参数传递给AnalyseSpeak就可以了,他能够完成中英文的混合发音。

当然,对于发音的暂定、继续、停止等操作,上面也给出了简单的方法调用,很容易明白。

下面简单介绍一下中文语音识别的方法:

先把该语音识别的类源代码贴在下面,然后再做说明:

 

public class SpRecognition

{

  private static SpRecognition _Instance = null ;

  private SpeechLib.ISpeechRecoGrammar isrg ;

  private SpeechLib.SpSharedRecoContextClass ssrContex =null;

  private System.Windows.Forms.Control cDisplay ;

  private SpRecognition()

  {

ssrContex = new SpSharedRecoContextClass() ;

isrg = ssrContex.CreateGrammar(1) ;

SpeechLib._ISpeechRecoContextEvents_RecognitionEventHandler recHandle = new _ISpeechRecoContextEvents_RecognitionEventHandler(ContexRecognition) ;

ssrContex.Recognition += recHandle ;

  }

  public void BeginRec(Control tbResult)

  {

isrg.DictationSetState(SpeechRuleState.SGDSActive) ;

cDisplay = tbResult ;

  }

  public static SpRecognition instance()

  {

if (_Instance == null)

  _Instance = new SpRecognition() ;

  return _Instance ;

  }

  public void CloseRec()

  {

isrg.DictationSetState(SpeechRuleState.SGDSInactive) ;

  }

  private void ContexRecognition(int iIndex,object obj,SpeechLib.SpeechRecognitionType type,SpeechLib.ISpeechRecoResult result)

  {

cDisplay.Text += result.PhraseInfo.GetText(0,-1,true) ;

  }

}

 

我们定义了ssrContex 和isrg为语音识别的上下文和语法,通过设置isrg的DictationSetState方法,我们可以开始或结束识别,在上面的程序中是BeginRec和CloseRec方法。cDisplay 是我们用来输出识别结果的地方,为了能够在大部分控件上都可以显示结果,我用了一个Control 类来定义它。当然,每次语音识别后都会触发ISpeechRecoContextEvents_RecognitionEventHandler 事件,我们定义了一个这样的方法ContexRecognition来响应事件,并且在这个方法里输出识别结果

发表在 article | 标签为 | C# Speech 中文发音已关闭评论

TTS 语音报价

在收费的时候程序自动报出价格,会给客人带来较好的感受。用的最早最普遍的可能就是公路收费系统了,但那是通过硬件来实现的。这里咱们用微软提供的语音开发包,用软件来实现一次:D 。
步骤如下:
1、在网上下载speechsdk51、speechsdk51LangPack这两个文件并安装,这是微软提供的语音开发包。
2、在VS里新建一个项目,引用语音库,如图:

点击查看原图

3、在窗体的按钮里这样写:
Private Sub Button
1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim v As New SpeechLib.SpVoice
        v.Speak(ChineseNum(CDec(TextBox1.Text)), SpeechLib.SpeechVoiceSpeakFlags.SVSFlagsAsync)
        MsgBox(ChineseNum(CDec(TextBox1.Text)))
End Sub
其实说话的只有这一句代码:
v.Speak(ChineseNum(CDec(TextBox1.Text)), SpeechLib.SpeechVoiceSpeakFlags.SVSFlagsAsync)
4、运行如图:

点击查看原图

这时一个动听的男音就会给您报出价格了,呵呵。
这位说什么?女音才能用“动听”?
。。。是的,但是想听女音吗?那就掏银子买开发包吧!
附:下面附上我用到的金额转达写函数
Public Function ChineseNum(ByVal Single_to As Decimal) As String
        Dim Str_to As String
        Dim PartStr() As String = {"", ""}
        Dim i As Integer
        Dim Full As Boolean = False
        Dim Zero As Boolean = False
        Dim Delimiters As Char = CChar(".")
        Str_to = CStr(Single_to)
       
        PartStr = Str_to.Split(Delimiters)
        Str_to = ""

        For i = 0 To PartStr(0).Length - 1
            Select Case PartStr(0).Chars(i)
                Case CChar("0")
                    If Zero = False Then
                        Zero = True
                    End If
                Case CChar("1")
                    If Zero = True Then
                        Str_to = Str_to.Insert(Str_to.Length, "零")
                        Zero = False
                    End If
                    Str_to = Str_to.Insert(Str_to.Length, "壹")
                Case CChar("2")
                    If Zero = True Then
                        Str_to = Str_to.Insert(Str_to.Length, "零")
                        Zero = False
                    End If
                    Str_to = Str_to.Insert(Str_to.Length, "贰")
                Case CChar("3")
                    If Zero = True Then
                        Str_to = Str_to.Insert(Str_to.Length, "零")
                        Zero = False
                    End If
                    Str_to = Str_to.Insert(Str_to.Length, "叁")
                Case CChar("4")
                    If Zero = True Then
                        Str_to = Str_to.Insert(Str_to.Length, "零")
                        Zero = False
                    End If
                    Str_to = Str_to.Insert(Str_to.Length, "肆")
                Case CChar("5")
                    If Zero = True Then
                        Str_to = Str_to.Insert(Str_to.Length, "零")
                        Zero = False
                    End If
                    Str_to = Str_to.Insert(Str_to.Length, "伍")
                Case CChar("6")
                    If Zero = True Then
                        Str_to = Str_to.Insert(Str_to.Length, "零")
                        Zero = False
                    End If
                    Str_to = Str_to.Insert(Str_to.Length, "陆")
                Case CChar("7")
                    If Zero = True Then
                        Str_to = Str_to.Insert(Str_to.Length, "零")
                        Zero = False
                    End If
                    Str_to = Str_to.Insert(Str_to.Length, "柒")
                Case CChar("8")
                    Str_to = Str_to.Insert(Str_to.Length, "捌")
                    Zero = False
                Case CChar("9")
                    If Zero = True Then
                        Str_to = Str_to.Insert(Str_to.Length, "零")
                        Zero = False
                    End If
                    Str_to = Str_to.Insert(Str_to.Length, "玖")
            End Select
            Select Case -(i - PartStr(0).Length + 1)
                Case 0
                    Str_to = Str_to.Insert(Str_to.Length, "元")
                Case 1
                    If Zero = False Then
                        Str_to = Str_to.Insert(Str_to.Length, "拾")
                    End If
                Case 2
                    If Zero = False Then
                        Str_to = Str_to.Insert(Str_to.Length, "佰")
                    End If
                Case 3
                    If Zero = False Then
                        Str_to = Str_to.Insert(Str_to.Length, "仟")
                    End If
                Case 4
                    Str_to = Str_to.Insert(Str_to.Length, "万")
                    Zero = False
                Case 5
                    If Zero = False Then
                        Str_to = Str_to.Insert(Str_to.Length, "拾")
                    End If
                Case 6
                    If Zero = False Then
                        Str_to = Str_to.Insert(Str_to.Length, "佰")
                    End If
                Case 7
                    If Zero = False Then
                        Str_to = Str_to.Insert(Str_to.Length, "仟")
                    End If
                Case 8
                    Str_to = Str_to.Insert(Str_to.Length, "亿")
                    Zero = False
                Case 9
                    Str_to = Str_to.Insert(Str_to.Length, "拾")
            End Select
        Next
       
        If PartStr.GetUpperBound(0) <> 0 Then
            For i = 0 To PartStr(1).Length - 1
                Select Case PartStr(1).Chars(i)
                    Case CChar("0")
                        Str_to = Str_to.Insert(Str_to.Length, "零")
                    Case CChar("1")
                        Str_to = Str_to.Insert(Str_to.Length, "壹")
                    Case CChar("2")
                        Str_to = Str_to.Insert(Str_to.Length, "贰")
                    Case CChar("3")
                        Str_to = Str_to.Insert(Str_to.Length, "叁")
                    Case CChar("4")
                        Str_to = Str_to.Insert(Str_to.Length, "肆")
                    Case CChar("5")
                        Str_to = Str_to.Insert(Str_to.Length, "伍")
                    Case CChar("6")
                        Str_to = Str_to.Insert(Str_to.Length, "陆")
                    Case CChar("7")
                        Str_to = Str_to.Insert(Str_to.Length, "柒")
                    Case CChar("8")
                        Str_to = Str_to.Insert(Str_to.Length, "捌")
                    Case CChar("9")
                        Str_to = Str_to.Insert(Str_to.Length, "玖")
                End Select
                If i = 0 Then
                    Str_to = Str_to.Insert(Str_to.Length, "角")
                Else
                    Str_to = Str_to.Insert(Str_to.Length, "分")
                    Full = True
                End If
            Next
        End If
        If Not Full Then
            Str_to = Str_to.Insert(Str_to.Length, "整")
        End If
        Return Str_to
    End Function



发表在 article | 标签为 | TTS 语音报价已关闭评论

Microsoft SQL Server 2005 Express 远程访问设置详述

概述
  Microsoft SQL Server 2005 Express Edition是Microsoft数据库的低端解决方案,是免费的,并且可以随软件免费发布,而就其数据库功能对于一般的企业级应用已足够了。但 默认安装时只允许本地访问,而不能远程访问。为了解决这种问题,网上有不少文章进行了介绍,但是都不全,如果你照着做,大都只完成了部份功能,而不能完全成功。本人查了大量资料,几次都想放弃,最终还是成功配置了,现写本文详细阐述 SQL Server 2005 Express Edition 启用网络访问,供大家参考。

  准备工作:1、安装 SQL Server 2005 Express Edition 并启用数据库服务;2、安装SQL Server 2005 Management Studio Express。

操作步骤
一、配置远程访问的协议(TCP)并启用端口:

   详细操作步骤请参照熊义龙的《SQL Server 2005 Express远程访问设置方法》写得非常详细且配有图文。感谢熊义龙朋友。

  在此补充:1、在上文中“第3步”启用TCP协议时,除了启用服务器的外网IP外,还要启用127.0.0.1以及IPAll的端口都设置好。2、也是上文“第3步”启用TCP协议时,建议设置一个静态的端口,三个要设置的端口都要统一。

二、启用“SQL Server 和 Windows 身份验证模式”:

   1、打开 SQL Server 2005 Management Studio Express(说明,写本文时,我用的SQL Server 企业版的管理器,操作是一样的)。服务器名(图中为NBFUQIN)右键,选择“属性”(如下图),即打开“服务器属性”对话框。

 点击查看原图

  2、在“服务器属性”对话框中,选择“选择页/安全性”,将“服务器身份验证”选为“SQL Server 和 Windows身份验证模式”,点击“确定”并重启数据库服务。如下图所示。

点击查看原图

三、增加SQL Server登录名或者开启SA远程访问:

   由于SQL Server 2005 Express Edition默认sa为禁止登录。所以要么开启sa登录,或者新建一个登录名即可。

   1、新建登录名:打开 SQL Server 2005 Management Studio Express,并选中“服务器名/安全性/登录名”,右击选择“新建登录名”,如下图所示。打开“登录名 - 新建”对话框。

 点击查看原图

  在“登录名—新建”对话框中,选择“常规”选项卡,然后新建一个登录名,要注意选中“SQL Server 身份验证”。如下图所示。

 点击查看原图

 

   选中“状态”选项卡,确保“登录”在“启用”状态、“是否允许连接到数据库引擎”处于“授予”状态。

 点击查看原图

  2、启用sa:在“登录”中,选中sa,右击“属性”,在“常规”中设置好密码,在“状态”中启用“登录”和授予“是否允许连接到数据库引擎”。

补充
  1、SQL Server 2005 Express Edition的登录的服务器与SQL Server 2005的其他版本(服务器即为“服务器IP或名称”)不同,它的服务器为“服务器IP\SQLexpress,1433”(也可用服务器名代替IP),后面的1433为第一步所启用的端口。  2、如果是XP做为服务器,还要在防火墙中开放对应的端口(当然你也可以关闭防火墙),如1433端口。

结束语
  以上就是整个配置过程的详细操作步骤,欢迎大家一起交流。在此还要感谢我的赵师弟。

 

发表在 article | 标签为 , | Microsoft SQL Server 2005 Express 远程访问设置详述已关闭评论

鼠标位置的检测,jQuery和YUI中的实现

 
jQuery中:

 

        if ( event.pageX == null && event.clientX != null ) {
            var doc = document.documentElement, body = document.body;
            event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
            event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
        }

YUI中:

            getPageX: function(ev) {
                var x = ev.pageX;
                if (!x && 0 !== x) {
                    x = ev.clientX || 0;
                    if ( this.isIE ) {
                        x += this._getScrollLeft();
                    }
                }
                return x;
            },

            getPageY: function(ev) {
                var y = ev.pageY;
                if (!y && 0 !== y) {
                    y = ev.clientY || 0;
                    if ( this.isIE ) {
                        y += this._getScrollTop();
                    }
                }
                return y;
            },

            _getScrollLeft: function() {
                return this._getScroll()[1];
            },

            _getScrollTop: function() {
                return this._getScroll()[0];
            },

            _getScroll: function() {
                var dd = document.documentElement, db = document.body;
                if (dd && (dd.scrollTop || dd.scrollLeft)) {
                    return [dd.scrollTop, dd.scrollLeft];
                } else if (db) {
                    return [db.scrollTop, db.scrollLeft];
                } else {
                    return [0, 0];
                }
            },
 

YUI的写法比起jQuery来确是“工程化”了很多,如果是按照代码行数发工资的话,推荐YUI,哈哈。之前翻译PPK的作品的是提到了无论如何都不要检测浏览器的类型,因为没必要,而且浏览器的UA都在胡言乱语。

 

关于document.documentElement和document.body
 
document.documentElement和document.body在不同的浏览器和不同的模式下面都会有不同的表现,已经有人做过详尽的测试了,地址在这里http://www.softcomplex.com/docs/get_window_size_and_scrollbar_position.html
经过测试的结论就是,在标准浏览器下面,一般都有相应代替的做法,在IE中,在documentElement存在的情况下一般都能正常显示,不存在时候使用document.body。这两个的来由应该源自HTML和xHTML。

 
所以在这个问题的处理上jQuery和YUI都采用了相同的办法:doc && doc.scrollLeft || body && body.scrollLeft || 0 。

关于pageX pageY和clientX clientY,scrollLeft scrollTop
 

对于鼠标事件,IE不支持通过pageX,pageY来获得鼠标在文档中的位置,而只有clientX、clientY,这两个参数只能获得鼠标在浏览器的可视范围内的位置。这时候就需要通过其他办法来获得鼠标在文档里面的位置,于是出现了scrollLeft和scrollTop。

有些情况下,“元素中内容(子元素)”的高度会超过“元素本身”的高度,这时候就使用scrollTop来表示超出部分的高度,scrollLeft同理。body元素的scrollTop就是指你的浏览器中被滚动条滚动了的高度。用这个值加上clientY不就是鼠标相对于文档的位置了么。在这里两个框架的也是相同的。event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0)

关于clientLeft和clientTop

然而jQuery中,以及网上搜索到的大量的实例中,还需要减掉clientLeft/Top值。

event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
 

这个值是做什么用的呢?可以先来查看下面的这幅图:

clientLeft的值其实就是元素的边框,YUI中没有减掉这个,难道是认为IE的body没有边框?我在IE下测试body确实有2px的clientLeft的值。所以如果要精确的得到鼠标的位置,在IE下面就必须减去这个clientLeft。
 

发表在 article | 标签为 | 鼠标位置的检测,jQuery和YUI中的实现已关闭评论

resin4.0.5+iis6 整合方案

安装jdk,并设置java_home等相关环境变量

下载resin4.0.5解压至D:\resin-pro-4.0.5
点击目录下的setup.exe,点击 web server plugins
看IIS,安装至 C:\Inetpub\Scripts ,如果没有Scripts目录,你得手动建一个,
安装后此目录下有个isapi_srun.dll,
然后在IIS上添加ISAPI,名称JSP,随便起也行,路径就是这文件
然后在添加一个.jsp的映射,也是这个文件,这些操作基本和php的一样。
最好在WEB服务器扩展也添加一个,然后让它允许。
然后在iis站点上新建一个虚拟目录,名称为Scripts,路径同上C:\Inetpub\Scripts
一般可能出错的地方就是IIS站点对这个目录或isapi_srun.dll没有读取权限,自己设。
还有isapi加载,那个优先级高低都可以的。只要是绿色就行。

------启动 resin   -->cmd -> net start resin
------这时打开IIS的站点,如果遇到.jsp文件,就会让resin解析了。

配置resin

-------------------D:\resin-pro-4.0.5\conf\resin.xml--------
大约在174行,修改 resin主机目录,和你IIS保持同路径
<web-app id="/" root-directory="WebRoot"/>
改成如:
<host id="b.oocms.net" root-directory="E:/Workspaces/ssh">

OK,只要你以上步骤正确操作,决对没问题

 

连接池要不要?要就在下面
大约在88行</resin:if>后面添加
    <database>
           <jndi-name>jdbc/aaa</jndi-name>
           <driver type="com.mysql.jdbc.Driver">
             <url>jdbc:mysql://127.0.0.1:3306/test</url>
             <user>root</user>
             <password>123</password>
            </driver>
            <prepared-statement-cache-size>8</prepared-statement-cache-size>
            <max-connections>20</max-connections>
            <max-idle-time>30s</max-idle-time>
    </database>
这样就可以直接在java里调用了,不需要像tomcat一样还得在web.xml配置

那在IIS上应该会了吧,resin上继续配置resin.xml
在</host>后面添加就是了
比如:
    <host id="www.oocms.net" root-directory="E:/Workspaces/ssh">
      <web-app id="/" root-directory="WebRoot"/>
    </host>

Resin多域名绑定 
 

需求: 
group.XXX.com 
XXX.group.XXX.com 
都指向同一系统

 
 

<host id="group.aaa.com"


>
  <host-alias-regexp>([a-zA-Z0-9.]+)roup\.([^.]+)\.com</host-alias-regexp>
  <host-name>${


host-alias-regexp.regexp[1]}


roup.${


host-alias-regexp.regexp[2]}


.com</host-name>
  <root-directory>.</root-directory>
  <web-app id="/"


 document-directory="e:\group_aaa"


/>
</host>

启动Resin后,访问

http://a.group.aaa.com/


http://group.aaa.com/


http://group.bbb.com/


http://a.group.bbb.com/





或另一配置方式


<host id="" root-directory=".">
<host-alias>域名1</host-alias>
<host-alias>域名2</host-alias>
<host-alias>域名3</host-alias>
     
    </host>

都能访问到同一系统。

-------------------------------------------------------------------------------

软件环境

  • 操作系统:win2003
  • SDK:JDK 1.6
  • 服务器:IIS6.0和Resin 3.1.2

1、配置Resin

  1. 安装好SDK(我的SDK安装在:C:\Program Files\Java\jdk),解压Resin至:C:\resin3.1
  2. 在我的电脑上单击鼠标右键→属性→高级→环境变量:
    1. 新建:java_home 值为:C:\Program Files\Java\jdk;
    2. 新建:Resin_home 值为:C:\resin3.1(Resin安装的目录);
    3. 新建:classpath 值为:.;C:\Program Files\Java\jdk\lib\dt.jar;C:\Program Files\Java\jdk\lib\tools.jar 前面有一个点和一个分号;
    4. 编辑系统变量:path加上一个分号,在其后面加上:C:\Program Files\Java\jdk\bin;

2、复制Resin文件至IIS目录

这就需要我们自己来复制文件。我的IIS是安装在C:\Inetpub下的:

  1. C:\Inetpub下面新建一个文件夹,重命名为scripts;
  2. 运行Rensin3.1下的setup.exe 选上iis/pws点OK,C:\Inetpub\scripts下就生成了isapi_srun.dll,如果失败请检查C:\Inetpub\scripts是否有权限;
  3. 在C:\Inetpub\scripts新建一个resin.ini文件。文件内容下面两行数据:
    ResinConfigServer localhost 6802
    IISPriority high


    官方的文档上说只有需要建立多个站点的时候才必须使用resin.ini。如果只有一个站点就没必要新建resin.ini(推荐使用);

4、设置IIS

  1. 在默认网站上单击右键→属性→ISAPI筛选器→添加:
    筛选器名称:Resin3.1(可随便填)
    可执行文件:C:\Inetpub\scripts\isapi_srun.dll
  2. 在默认网站上单击右键→新建→虚拟目录
    别名:scripts
    本地路径:C:\Inetpub\scripts
  3. 单击WEB服务扩展→添加一个新的WEB服务扩展
    扩展名:Resin(可随便添)
    要求文件:C:\Inetpub\scripts\isapi_srun.dll
    选中设置扩展状态为允许

5、设置Resin

打开C:\resin3.1\conf\resin.conf,在文件中找到(大概是在最后):

<host id=''>
<document-directory>doc</document-directory>

改成

<host id=''>
<document-directory>c:/inetpub/wwwroot</document-directory>

(c:/inetpub/wwwroot,为你的默认网站的目录)

然后先运行net stop w3svc关闭IIS服务;再运行net start w3svc重新启动IIS;打开Resin3.1\bin\httpd.exe。现在IIS6.0与Resin3.1已经成功整合了。

我们可以将httpd.exe作为服务启动。那么,计算机启动的时候就会启动httpd.exe:

  • 安装服务:c:\resin3.1\bin\httpd.exe -install
  • 取消服务:c:\resin3.1\bin\httpd.exe -remove

启动后访问IIS站点如果出现Server is currently unavailable or down for maintenance,运行resin下的setup.exe文件,点remove关闭窗口即可(注意点完remove后不要点OK,直接X就行了。)

发表在 web server | 标签为 , | resin4.0.5+iis6 整合方案已关闭评论

Linux网络配置

ifconfig 配置网络接口的工具介绍;

ifconfig 是一个用来查看、配置、启用或禁用网络接口的工具,这个工具极为常用的。比如我们可以用这个工具来临时性的配置网卡的IP地址、掩码、广播地址、网关等。 也可以把它写入一个文件中(比如/etc/rc.d/rc.local),这样系统引导后,会读取这个文件,为网卡设置IP地址;不过这样做目前看来没有 太大的必要。主要是各个发行版本都有自己的配置工具,无论如何也能把主机加入到网络中;

下面我们看看ifconfig 用法;

ifconfig 查看网络接口状态;

ifconfig 如果不接任何参数,就会输出当前网络接口的情况;

[root@localhost ~]# ifconfigeth0      Link encap:Ethernet  HWaddr 00:C0:9F:94:78:0E          inet addr:192.168.1.88  Bcast:192.168.1.255  Mask:255.255.255.0          inet6 addr: fe80::2c0:9fff:fe94:780e/64 Scope:Link          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1          RX packets:850 errors:0 dropped:0 overruns:0 frame:0          TX packets:628 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:1000          RX bytes:369135 (360.4 KiB)  TX bytes:75945 (74.1 KiB)          Interrupt:10 Base address:0x3000lo        Link encap:Local Loopback          inet addr:127.0.0.1  Mask:255.0.0.0          inet6 addr: ::1/128 Scope:Host          UP LOOPBACK RUNNING  MTU:16436  Metric:1          RX packets:57 errors:0 dropped:0 overruns:0 frame:0          TX packets:57 errors:0 dropped:0 overruns:0 carrier:0          collisions:0 txqueuelen:0          RX bytes:8121 (7.9 KiB)  TX bytes:8121 (7.9 KiB)解说:
eth0 表示第一块网卡, 其中 HWaddr 表示网卡的物理地址,我们可以看到目前这个网卡的物理地址(MAC地址)是 00:C0:9F:94:78:0E ; inet addr 用来表示网卡的IP地址,此网卡的 IP地址是 192.168.1.88, 广播地址, Bcast:192.168.1.255,掩码地址Mask:255.255.255.0

lo 是表示主机的回坏地址,这个一般是用来测试一个网络程序,但又不想让局域网或外网的用户能够查看,只能在此台主机上运行和查看所用的网络接口。比如我们把 HTTPD服务器的指定到回坏地址,在浏览器输入 127.0.0.1 就能看到你所架WEB网站了。但只是您能看得到,局域网的其它主机或用户无从知道;

如果我们想知道主机所有网络接口的情况,请用下面的命令;

[root@localhost ~]# ifconfig -a
如果我们想查看某个端口,比如我们想查看eth0 的状态,就可以用下面的方法;

[root@localhost ~]# ifconfig eth0

ifconfig 配置网络接口;

ifconfig 可以用来配置网络接口的IP地址、掩码、网关、物理地址等;值得一说的是用ifconfig 为网卡指定IP地址,这只是用来调试网络用的,并不会更改系统关于网卡的配置文件。如果您想把网络接口的IP地址固定下来,目前有三个方法:一是通过各个 发行和版本专用的工具来修改IP地址;二是直接修改网络接口的配置文件;三是修改特定的文件,加入ifconfig 指令来指定网卡的IP地址,比如在redhat或Fedora中,把ifconfig 的语名写入/etc/rc.d/rc.local文件中;

ifconfig 配置网络端口的方法:

ifconfig 工具配置网络接口的方法是通过指令的参数来达到目的的,我们只说最常用的参数;

ifconfig 网络端口 IP地址 hw <HW> MAC地址 netmask 掩码地址 broadcast 广播地址 [up/down]
* 实例一:
比如我们用ifconfig 来调试 eth0网卡的地址

[root@localhost ~]# ifconfig eth0 down
[root@localhost ~]# ifconfig eth0 192.168.1.99 broadcast 192.168.1.255 netmask 255.255.255.0
[root@localhost ~]# ifconfig eth0 up
[root@localhost ~]# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:11:00:00:11:11
          inet addr:192.168.1.99 Bcast:192.168.1.255 Mask:255.255.255.0
          UP BROADCAST MULTICAST MTU:1500 Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
          Interrupt:11 Base address:0x3400
注解: 上面的例子我们解说一下;

第一行:ifconfig eth0 down 表示如果eth0是激活的,就把它DOWN掉。此命令等同于 ifdown eth0;
第二行:用ifconfig 来配置 eth0的IP地址、广播地址和网络掩码;
第三行:用ifconfig eth0 up 来激活eth0 ; 此命令等同于 ifup eth0
第四行:用 ifconfig eth0 来查看 eth0的状态;

当然您也可以用直接在指令IP地址、网络掩码、广播地址的同时,激活网卡;要加up参数;比如下面的例子;

[root@localhost ~]# ifconfig eth0 192.168.1.99 broadcast 192.168.1.255 netmask 255.255.255.0 up
* 实例二:在这个例子中,我们要学会设置网络IP地址的同时,学会设置网卡的物理地址(MAC地址);

比如我们设置网卡eth1的IP地址、网络掩码、广播地址,物理地址并且激活它;

[root@localhost ~]# ifconfig eth1 192.168.1.252 hw ether 00:11:00:00:11:11 netmask 255.255.255.0 broadcast 192.168.1.255 up

[root@localhost ~]# ifconfig eth1 hw ether 00:11:00:00:11:22
[root@localhost ~]# ifconfig eth1 192.168.1.252 netmask 255.255.255.0 broadcast 192.168.1.255 up
其中 hw 后面所接的是网络接口类型, ether表示乙太网, 同时也支持 ax25 、ARCnet、netrom等,详情请查看 man ifconfig ;

如何用ifconfig 来配置虚拟网络接口;

有时我们为了满足不同的需要还需要配置虚拟网络接口,比如我们用不同的IP地址来架运行多个HTTPD服务器,就要用到虚拟地址;这样就省却了同一个IP地址,如果开设两个的HTTPD服务器时,要指定端口号。

虚拟网络接口指的是为一个网络接口指定多个IP地址,虚拟接口是这样的 eth0:0 、 eth0:1、eth0:2 ... .. eth1N。当然您为eth1 指定多个IP地址,也就是 eth1:0、eth1:1、eth1:2 ... ...以此类推;

其实用ifconfig 为一个网卡配置多个IP地址,就用前面我们所说的ifconfig的用法,这个比较简单;看下面的例子;

[root@localhost ~]# ifconfig eth1:0 192.168.1.251 hw ether 00:11:00:00:11:33 netmask 255.255.255.0 broadcast 192.168.1.255 up

[root@localhost ~]# ifconfig eth1 hw ether 00:11:00:00:11:33
[root@localhost ~]# ifconfig eth1 192.168.1.251 netmask 255.255.255.0 broadcast 192.168.1.255 up
注意:指定时,要为每个虚拟网卡指定不同的物理地址;

在 Redhat/Fedora 或与Redhat/Fedora类似的系统,您可以把配置网络IP地址、广播地址、掩码地址、物理地址以及激活网络接口同时放在一个句子中,写入/etc/rc.d/rc.local中。比如下面的例子;

ifconfig eth1:0 192.168.1.250 hw ether 00:11:00:00:11:44 netmask 255.255.255.0 broadcast 192.168.1.255 up
ifconfig eth1:1 192.168.1.249 hw ether 00:11:00:00:11:55 netmask 255.255.255.0 broadcast 192.168.1.255 up
解说:上面是为eth1的网络接口,设置了两个虚拟接口;每个接口都有自己的物理地址、IP地址... ...

如何用ifconfig 来激活和终止网络接口的连接;

激活和终止网络接口的用 ifconfig 命令,后面接网络接口,然后加上 down或up参数,就可以禁止或激活相应的网络接口了。当然也可以用专用工具ifup和ifdown 工具;

[root@localhost ~]# ifconfig eth0 down
[root@localhost ~]# ifconfig eth0 up
[root@localhost ~]# ifup eth0
[root@localhost ~]# ifdown eth0
对于激活其它类型的网络接口也是如此,比如 ppp0,wlan0等;不过只是对指定IP的网卡有效。

注意:对DHCP自动分配的IP,还得由各个发行版自带的网络工具来激活;当然得安装dhcp客户端;这个您我们应该明白;

比如Redhat/Fedora

[root@localhost ~]# /etc/init.d/network start
Slackware 发行版;

[root@localhost ~]# /etc/rc.d/rc.inet1

Redhat/Fedora 网络接口的配置文件和网络接口专用配置工具;

在Redhat/Fedora 中,与乙太网卡相关的配置文件位于 /etc/sysconfig/network-scripts目录中,比如 ifcfg-eth0、ifcfg-eth1 .... ....

Redhat/Fedora 或类似这样的系统,网卡的配置文件;

比如在Fedora 5.0中,ifcfg-eth0 ;

如果您用DHCP服务器来自动获取IP的,一般情况下ifcfg-eth0的内容是类似下面这样的;

DEVICE=eth0
ONBOOT=yes
BOOTPROTO=dhcp
TYPE=Ethernet
如果您是指定IP的,一般内容是类似下面的;

DEVICE=eth0 注:网络接口
ONBOOT=yes 注:开机引导时激活
BOOTPROTO=static 注:采用静态IP地址;
IPADDR=192.168.1.238 注:IP地址
NETMASK=255.255.255.0 注:网络掩码;
GATEWAY=192.168.1.1 注:网关;
下面的几个选项也可以利用;

HOSTNAME=linxsir03 注:指定主机名;
DOMAIN=localdomain 注:指定域名;
HWADDR=00:00:11:22:00:aa 注:指定网卡硬件地址 (MAC地址), 也可以省略,不过这在这里来更改MAC地址一般是不能生效的。还是通过前面所说的ifconfig的办法来更改吧;

 

Redhat/Fedora 或类似系统, 配置网络的工具介绍 ;

在Redhat早期的版本中, 有linuxconf 、redhat-config-network 、netconfig 等工具;

在Redhat/Fedora 最新的版本有 system-config-network-tui (文本模式的) 、system-config-network (图形模式的),netconfig(文本模式的)。

这些工具都会直接修改Linux系统中关于网络接口的配置文件;这是 ifconfig 所不能比的;

其中 redhat-config-network 和system-config-network工具不仅仅是配置网卡的工具,还有配置ISDN和普通猫、ADSL的工具、网络硬件的添加、主机名字的配置、DNS各客户端的配置等。其实是一个工具组的集成;

这些工具比较简单,以root权限运行命令就能调用,比如:

[root@localhost ~]# /usr/sbin/system-config-network
[root@localhost ~]# system-config-network
如果您设置了可执行命令的环境变量,不用加路径就可以运行,但前提是您得安装这个网络管理工具;

不过值得一说的是netconfig 工具是一个在文本模式比较好的工具,推荐大家使用;理由是这个工具在文本模式下,也有一个简单的图形界面;还有命令模式;功能强着呢;

[root@localhost ~]# netconfig -d eth0 注:配置eth0
[root@localhost ~]# netconfig -d eth1 注:配置eth1

Redhat/Fedora系统中的netconfig 特别介绍;

netconfig这个工具,在Redhat/Fedora 或类似于它们的系统中都是存在的,这个工具比较强大。所以特别介绍一下。但在Slackware中netconfig是TEXT模式下有一个图形模式,但不能象ifconfig一样用命令来操作网卡接口;

netconfig 的用法如下:

[root@localhost ~]# netconfig --help 注:帮助;
  --bootproto=(dhcp|bootp|none) Boot protocol to use(
  --gateway=STRING Network gateway(指定网关)
  --ip=STRING IP address(指定IP地址)
  --nameserver=STRING Nameserver(指定DNS客户端)
  --netmask=STRING Netmask(指定网络掩码)
  --hostname=STRING Hostname( 指定主机名)
  --domain=STRING Domain name(指定域名)
  -d, --device=STRING Network device (指定网络设备)
  --nodns No DNS lookups (没有DNS查询)
  --hwaddr=STRING Ethernet hardware address (指定网卡的物理地址)
  --description=STRING Description of the device (描述性文字)
Help options: (帮助选项)
  -?, --help Show this help message
  --usage Display brief usage message
实例一:设置网卡的DHCP模式自动获得IP

[root@localhost ~]# netconfig -d eth0 --bootproto=dhcp
实例一:手动设置网卡的IP等

[root@localhost ~]# netconfig -d eth0 --ip=192.168.1.33 --netmask=255.255.255.0 --gateway=192.168.1.1

发表在 article | 标签为 | 28条评论

sql 中contains的使用例子,参数详解

全文索引——CONTAINS 语法

 

Like直接在数据据中查找可以查到所有所需记录但是会扫描整个表会影响性能CONTAINS是基于全文索引进行查询,查询结果受系统全文索引分词的方法影响查询结果会不全。
Select * FROM A Where CONTAINS(B,'"IT"Or"理论"')5257条记录
Select * FROM A Where B Like'%IT%' or B LIKE '%理论%' 5468条记录
结论:需要精确查询用Like如产品搜索,内容搜索可以用CONTAINS提高效率。

我们通常在 WHERE 子句中使用 CONTAINS ,就象这样:SELECT * FROM table_name WHERE CONTAINS(fullText_column,'search contents')。

我们通过例子来学习,假设有表 students,其中的 address 是全文本检索的列。
1. 查询住址在北京的学生
SELECT student_id,student_name
FROM students
WHERE CONTAINS( address, 'beijing' )
remark: beijing是一个单词,要用单引号括起来。

2. 查询住址在河北省的学生
SELECT student_id,student_name
FROM students
WHERE CONTAINS( address, '"HEIBEI province"' )
remark: HEBEI province是一个词组,在单引号里还要用双引号括起来。

3. 查询住址在河北省或北京的学生
SELECT student_id,student_name
FROM students
WHERE CONTAINS( address, '"HEIBEI province" OR beijing' )
remark: 可以指定逻辑操作符(包括 AND ,AND NOT,OR )。

4. 查询有 '南京路' 字样的地址
SELECT student_id,student_name
FROM students
WHERE CONTAINS( address, 'nanjing NEAR road' )
remark: 上面的查询将返回包含 'nanjing road','nanjing east road','nanjing west road' 等字样的地址。
A NEAR B,就表示条件: A 靠近 B。

5. 查询以 '湖' 开头的地址
SELECT student_id,student_name
FROM students
WHERE CONTAINS( address, '"hu*"' )
remark: 上面的查询将返回包含 'hubei','hunan' 等字样的地址。
记住是 *,不是 %。

6. 类似加权的查询
SELECT student_id,student_name
FROM students
WHERE CONTAINS( address, 'ISABOUT (city weight (.8), county wright (.4))' )
remark: ISABOUT 是这种查询的关键字,weight 指定了一个介于 0~1之间的数,类似系数(我的理解)。表示不同条件有不同的侧重。

7. 单词的多态查询
SELECT student_id,student_name
FROM students
WHERE CONTAINS( address, 'FORMSOF (INFLECTIONAL,street)' )
remark: 查询将返回包含 'street','streets'等字样的地址。
对于动词将返回它的不同的时态,如:dry,将返回 dry,dried,drying 等等。

以上例子都使用英文,不使用中文是因为有的查询方式中文不支持,而且我的计算机是英文系统。
全文索引——CONTAINS 语法
我们通常在 WHERE 子句中使用 CONTAINS ,就象这样:SELECT * FROM table_name WHERE CONTAINS(fullText_column,'search contents')。

如果你在选定字段中查询一个匹配的直接使用
如:
从company中检查是否有test1的则:
select * from company
where contains(*,'test1')
如果要检查的是两个关键字,如是或地关系:
select * from company
where contains(*,'"北京" or "tttt"')
注意:关键字“北京”和“tttt”必须用"",包括起来,or代表两个关键字之间是"或"的关系
如果是与的关系:
select * from company
where contains(*,'"北京" and "tttt"')
如果是三个关键字则:
关键字前的那个or或者and 表示跟其他关键字的关系
and 表示两个词是靠近的

发表在 article | 标签为 , | sql 中contains的使用例子,参数详解已关闭评论

JQuery 扩展

免得到时再到处查询,把这些链接直接引过来算了,有机会都熟悉了再整理下
一、文件上传类(File upload)
Ajax File Upload

jQUploader
.
Multiple File Upload plugin
.
jQuery File Style
.
Styling an input type file
.
Progress Bar Plugin
.
二、表单验证(Form Validation)
jQuery Validation
.
Auto Help
.
Simple jQuery form validation
.
jQuery XAV - form validations
.
jQuery AlphaNumeric
.
Masked Input
.
TypeWatch Plugin
.
Text limiter for form fields
.
Ajax Username Check with jQuery
.
三、表单-选取框(Form - Select Box stuff)
jQuery Combobox
.
jQuery controlled dependent (or Cascadign) Select List
.
Multiple Selects
.
Select box manipulation
.
Select Combo Plugin
.
jQuery - LinkedSelect

Auto-populate multiple select boxes
.
Choose Plugin (Select Replacement)
.
四、表单基本、输入框、选择框等(Form Basics, Input Fields, Checkboxes etc.)
jQuery Form Plugin
.
jQuery-Form
.
jLook Nice Forms
.
jNice
.
Ping Plugin
.
Toggle Form Text
.
ToggleVal
.
jQuery Field Plugin
.
jQuery Form’n Field plugin
.
jQuery Checkbox manipulation
.
jTagging
.
jQuery labelcheck
.
Overlabel
.
3 state radio buttons
.
ShiftCheckbox jQuery Plugin
.
Watermark Input
.
jQuery Checkbox (checkboxes with imags)
.
jQuery SpinButton Control
.
jQuery Ajax Form Builder
.
jQuery Focus Fields
.
jQuery Time Entry
.
五、时间、日期和颜色选取(Time, Date and Color Picker)
jQuery UI Datepicker
.
jQuery date picker plugin
.
jQuery Time Picker
.
Time Picker
.
ClickPick
.
TimePicker
.
Farbtastic jQuery Color Picker Plugin
.
Color Picker by intelliance.fr
.
六、投票插件(Rating Plugins)
jQuery Star Rating Plugin
.
jQuery Star Rater
.
Content rater with asp.net, ajax and jQuery
.
Half-Star Rating Plugin
.
七、搜索插件(Search Plugins)
jQuery Suggest
.
jQuery Autocomplete
.
jQuery Autocomplete Mod
.
jQuery Autocomplete by AjaxDaddy
.
jQuery Autocomplete Plugin with HTML formatting
.
jQuery Autocompleter
.
AutoCompleter (Tutorial with PHP&MySQL)
.
quick Search jQuery Plugin
.
八、编辑器(Inline Edit & Editors)
jTagEditor
.
WYMeditor
.
jQuery jFrame
.
Jeditable - edit in place plugin for jQuery
.
jQuery editable
.
jQuery Disable Text Select Plugin
.
Edit in Place with Ajax using jQuery
.
jQuery Plugin - Another In-Place Editor
.
TableEditor
.
tEditable - in place table editing for jQuery
.
九、多媒体、视频、Flash等(Audio, Video, Flash, SVG, etc)
jMedia - accessible multi-media embedding
.
JBEdit - Ajax online Video Editor
.
jQuery MP3 Plugin
.
jQuery Media Plugin
.
jQuery Flash Plugin
.
Embed QuickTime
.
SVG Integration
.
十、图片(Photos/Images/Galleries)
ThickBox
.
jQuery lightBox plugin
.
jQuery Image Strip
.
jQuery slideViewer
.
jQuery jqGalScroll 2.0
.
jQuery - jqGalViewII
.
jQuery - jqGalViewIII
.
jQuery Photo Slider
.
jQuery Thumbs - easily create thumbnails
.
jQuery jQIR Image Replacement
.
jCarousel Lite
.
jQPanView
.
jCarousel
.
Interface Imagebox
.
Image Gallery using jQuery, Interface & Reflactions
.
simple jQuery Gallery
.
jQuery Gallery Module
.
EO Gallery
.
jQuery ScrollShow
.
jQuery Cycle Plugin
.
jQuery Flickr
.
jQuery Lazy Load Images Plugin
.
Zoomi - Zoomable Thumbnails
.
jQuery Crop - crop any image on the fly
.
Image Reflection
.
十一、Google地图(Google Map)
jQuery Plugin googlemaps
.
jMaps jQuery Maps Framework
.
jQmaps
.
jQuery & Google Maps
.
jQuery Maps Interface forr Google and Yahoo maps
.
jQuery J Maps - by Tane Piper
.
十二、游戏(Games)
Tetris with jQuery
.
jQuery Chess
.
Mad Libs Word Game
.
jQuery Puzzle
.
jQuery Solar System (not a game but awesome jQuery Stuff)
.
十三、表格等(Tables, Grids etc.)
UI/Tablesorter
.
jQuery ingrid
.
jQuery Grid Plugin
.
Table Filter - awesome!
.
TableEditor
.
jQuery Tree Tables
.
Expandable “Detail” Table Rows
.
Sortable Table ColdFusion Costum Tag with jQuery UI
.
jQuery Bubble
.
TableSorter
.
Scrollable HTML Table
.
jQuery column Manager Plugin
.
jQuery tableHover Plugin
.
jQuery columnHover Plugin
.
jQuery Grid
.
TableSorter plugin for jQuery
.
tEditable - in place table editing for jQuery
.
jQuery charToTable Plugin
.
jQuery Grid Column Sizing
.
jQuery Grid Row Sizing
.
十四、统计图(Charts, Presentation etc.)
jQuery Wizard Plugin
.
jQuery Chart Plugin
.
Bar Chart
.
十五、边框、圆角、背景(Border, Corners, Background)
jQuery Corner
.
jQuery Curvy Corner
.
Nifty jQuery Corner
.
Transparent Corners
.
jQuery Corner Gallery
.
Gradient Plugin
.
十六、文字和超链接(Text and Links)
jQuery Spoiler plugin
.
Text Highlighting
.
Disable Text Select Plugin
.
jQuery Newsticker
.
Auto line-height Plugin
.
Textgrad - a text gradient plugin
.
LinkLook - a link thumbnail preview
.
pager jQuery Plugin
.
shortKeys jQuery Plugin
.
jQuery Biggerlink
.
jQuery Ajax Link Checker
.
十七、鼠标提示(Tooltips)
jQuery Plugin - Tooltip
.
jTip - The jQuery Tool Tip
.
clueTip
.
BetterTip
.
Flash Tooltips using jQuery
.
ToolTip
.
十八、菜单和导航(Menus, Navigations)
jQuery Tabs Plugin - awesome!
. [demo nested tabs
.]
another jQuery nested Tab Set example (based on jQuery Tabs Plugin)
.
jQuery idTabs
.
jdMenu - Hierarchical Menu Plugin for jQuery
.
jQuery SuckerFish Style
.
jQuery Plugin Treeview
.
treeView Basic
.
FastFind Menu
.
Sliding Menu
.
Lava Lamp jQuery Menu
.
jQuery iconDock
.
jVariations Control Panel
.
ContextMenu plugin
.
clickMenu
.
CSS Dock Menu
.
jQuery Pop-up Menu Tutorial
.
Sliding Menu
.
http://stilbuero.de/jquery/tabs_3/

十九、幻灯、翻转等(Accordions, Slide and Toggle stuff)
jQuery Plugin Accordion
.
jQuery Accordion Plugin Horizontal Way
.
haccordion - a simple horizontal accordion plugin for jQuery
.
Horizontal Accordion by portalzine.de
.
HoverAccordion
.
Accordion Example from fmarcia.info
.
jQuery Accordion Example
.
jQuery Demo - Expandable Sidebar Menu
.
Sliding Panels for jQuery
.
jQuery ToggleElements
.
Coda Slider
.
jCarousel
.
Accesible News Slider Plugin
.
Showing and Hiding code Examples
.
jQuery Easing Plugin
.
jQuery Portlets
.
AutoScroll
.
Innerfade
.
二十、拖放插件(Drag and Drop)
UI/Draggables
.
EasyDrag jQuery Plugin
.
jQuery Portlets
.
jqDnR - drag, drop resize
.
Drag Demos
.
二十一、XML XSL JSON Feeds
XSLT Plugin
.
jQuery Ajax call and result XML parsing
.
xmlObjectifier - Converts XML DOM to JSON
.
jQuery XSL Transform
.
jQuery Taconite - multiple Dom updates
.
RSS/ATOM Feed Parser Plugin
.
jQuery Google Feed Plugin
.
二十二、浏览器(Browserstuff)
Wresize - IE Resize event Fix Plugin
.
jQuery ifixpng
.
jQuery pngFix
.
Link Scrubber - removes the dotted line onfocus from links
.
jQuery Perciformes - the entire suckerfish familly under one roof
.
Background Iframe
.
QinIE - for proper display of Q tags in IE
.
jQuery Accessibility Plugin
.
jQuery MouseWheel Plugin
.
二十三、对话框、确认窗口(Alert, Prompt, Confirm Windows)
jQuery Impromptu
.[注:很值得使用]

jQuery Confirm Plugin
.
jqModal
.
SimpleModal
.[注:很值得使用]

二十四、CSS
jQuery Style Switcher
.
JSS - Javascript StyleSheets
.
jQuery Rule - creation/manipulation of CSS Rules
.
jPrintArea
.
二十五、DOM、AJAX和其它JQuery插件(DOM, Ajax and other jQuery plugins)
FlyDOM
.
jQuery Dimenion Plugin
.
jQuery Loggin
.
Metadata - extract metadata from classes, attributes, elements
.
Super-tiny Client-Side Include Javascript jQuery Plugin
.
Undo Made Easy with Ajax
.
JHeartbeat - periodically poll the server
.
Lazy Load Plugin
.
Live Query
.
jQuery Timers
.
jQuery Share it - display social bookmarking icons
.
jQuery serverCookieJar
.
jQuery autoSave
.
jQuery Puffer
.
jQuery iFrame Plugin
.
Cookie Plugin for jQuery
.
jQuery Spy - awesome plugin
.
Effect Delay Trick
.
jQuick - a quick tag creator for jQuery
.
Metaobjects

.
elementReady

发表在 article | 标签为 | JQuery 扩展已关闭评论

C++操作符及优先级

C++操作符的优先级

 

 

C++ 操作符的优先级

操作符及其结合性

功能

用法

L
L
L
::
::
::
全局作用域 
类作用域 
名字空间作用域
::name
class::name
namespace::name
L
L
L
L
L
 
.
->
[]
()
()
 
成员选择 
成员选择 
下标 
函数调用 
类型构造 
 
object.member
pointer->member
variable[expr]
name(expr_list)
type(expr_list)
R
R
R
R
R
 
++
--
typeid
typeid
显示强制类型转换 
 
后自增操作 
后自减操作 
类型ID
运行时类型ID
类型转换 
 
lvalue++
lvalue--
typeid(type)
typeid(expr)
cast_name<type>(expr)
R
R
R
R
R
R
R
R
R
R
R
R
R
R
sizeof
sizeof
++
--
~
!
-
+
*
&
()
new
delete
delete[]
对象的大小 
类型的大小 
前自增操作 
前自减操作 
位求反 
逻辑非 
一元负号 
一元正号 
解引用 
取地址 
类型转换 
创建对象 
释放对象 
释放数组
sizeof expr
sizeof(type)
++lvalue
--lvalue
~expr
!expr
-expr
+expr
*expr
&expr
(type)expr
new type
delete expr
delete []expr
L
L
->*
.*
指向成员操作的指针 
指向成员操作的指针
ptr->*ptr_to_member
obj.*ptr_to_member
L
L
L
*
/
%
乘法 
除法 
求模(求余)
expr * expr
expr / expr
expr % expr
L
L
+
-
加法 
减法
expr + expr
expr - expr
L
L
<< 
>>
位左移 
位右移
expr << expr
expr >> expr
L
L
L
L

<=

>=
小于 
小于或等于 
大于 
大于或等于
expr < expr
expr <= expr
expr > expr
expr >= expr
L
R
==
!=
相等 
不等
Expr == expr
Expr != expr
R & 位与 Expr & expr
R ^ 位异或 Expr ^ expr
R | 位或 Expr | expr
R && 逻辑与 Expr && expr
R || 逻辑或 Expr || expr
R ?: 条件操作 Expr ? expr:expr
R
R
R
R
R
=
*=,/=,%=
+=,-=
<<=,>>=
&=,|=,^=
赋值操作 
复合赋值操作 

 

Lvalue= expr
Lvalue+= expr
…… 

 

R throw 抛出异常 Throw expr
L , 逗号 Expr, expr
 

 

记忆方法:
--摘自《C语言程序设计实用问答》      
    问题:如何记住运算符的15种优先级和结合性?   
    解答:C语言中运算符种类比较繁多,优先级有15种,结合性有两种。   
    如何记忆两种结合性和15种优先级?下面讲述一种记忆方法。   
    结合性有两种,一种是自左至右,另一种是自右至左,大部分运算符的结合性是自左至右,只有单目运算符、三目运算符的赋值运算符的结合性自右至左。   
    优先级有15种。记忆方法如下:   
    记住一个最高的:构造类型的元素或成员以及小括号。   
    记住一个最低的:逗号运算符。   
    剩余的是一、二、三、赋值。   
    意思是单目、双目、三目和赋值运算符。   
    在诸多运算符中,又分为:   
    算术、关系、逻辑。   
    两种位操作运算符中,移位运算符在算术运算符后边,逻辑位运算符在逻辑运算符的前面。再细分如下:   
    算术运算符分     *,/,%高于+,-。   
    关系运算符中,〉,〉=,<,<=高于==,!=。   
    逻辑运算符中,除了逻辑求反(!)是单目外,逻辑与(&&)高于逻辑或(||)。   
    逻辑位运算符中,除了逻辑按位求反(~)外,按位与(&)高于按位半加(^),高于按位或(|)。   
    这样就将15种优先级都记住了,再将记忆方法总结如下:   
    去掉一个最高的,去掉一个最低的,剩下的是一、二、三、赋值。双目运算符中,顺序为算术、关系和逻辑,移位和逻辑位插入其中。

发表在 article | 标签为 | 262条评论

用HASH表进行海量数据搜索

提一个简单的问题,如果有一个庞大的字符串数组,然后给你一个单独的字符串,让你从这个数组中查找是否有这个字符串并找到它,你会怎么做?有一个方法最简单,老老实实从头查到尾,一个一个比较,直到找到为止,我想只要学过程序设计的人都能把这样一个程序作出来,但要是有程序员把这样的程序交给用户,我只
能用无语来评价,或许它真的能工作,但...也只能如此了。最合适的算法自然是使用HashTable(哈希表),先介绍介绍其中的基本知识,所谓Hash,一般是一个整数,通过某种算法,可以把一个字符串"压缩" 成一个整数,这个数称为Hash,当然,无论如何,一个32位整数是无法对应回一个字符串的,但在程序中,两个字符
串计算出的Hash值相等的可能非常 小,下面看看在MPQ中的Hash算法
unsigned long HashString(char *lpszFileName, unsigned long dwHashType)
{
unsigned char *key = (unsigned char *)lpszFileName;
unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;
int ch;
while(*key != 0)
{
ch = toupper(*key++);
seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
return seed1;
}
Blizzard的这个算法是非常高效的,被称为"One-Way Hash",举个例子,字符串"unitneutralacritter.grp"通过这个算法得到的结果是0xA26067F3。
是 不是把第一个算法改进一下,改成逐个比较字符串的Hash值就可以了呢,答案是,远远不够,要想得到最快的算法,就不能进行逐个的比较,通常是构造一个哈 希表(Hash Table)来解决问题,哈希表是一个大数组,这个数组的容量根据程序的要求来定义,例如1024,每一个Hash值通过取模运算 (mod)对应到数组中的一个位置,这样,只要比较这个字符串的哈希值对应的位置又没有被占用,就可以得到最后的结果了,想想这是什么速度?是的,是最快 的O(1),现在仔细看看这个算法吧
int GetHashTablePos(char *lpszString, SOMESTRUCTURE *lpTable, int nTableSize)

{
int nHash = HashString(lpszString), nHashPos = nHash % nTableSize;
if (lpTable[nHashPos].bExists && !strcmp(lpTable[nHashPos].pString, lpszString
))
return nHashPos;
else
return -1; //Error value
}
看 到此,我想大家都在想一个很严重的问题:"如果两个字符串在哈希表中对应的位置相同怎么办?",毕竟一个数组容量是有限的,这种可能性很大。解决该问题的 方法很多,我首先想到的就是用"链表",大学里学的数据结构教会了这个百试百灵的法宝,我遇到的很多算法都可以转化成链表来解决,只要在哈希表的每个 入口挂一个链表,保存所有对应的字符串就OK了。事情到此似乎有了完美的结局,如果是把问题独自交给我解决,此时我可能就要开始定义数据结构然后写代码了。然而Blizzard的程序员使用的方法则是更精妙的方法。基本原理就是:他们在哈希表中不是用一个哈希值而是用三个哈希值来校验字符串。中 国有句古话"再一再二不能再三再四",看来Blizzard也深得此话的精髓,如果说两个不同的字符串经过一个哈希算法得到的入口点一致有可能,但用三个 不同的哈希算法算出的入口点都一致,那几乎可以肯定是不可能的事了,这个几率是:1888946593147858085478
4,大概是10的 22.3次方分之一,对一个游戏程序来说足够安全了。现在再回到数据结构上,Blizzard使用的哈希表没有使用链表,而采用"顺延"的方式来解决问题,看看这个算法:
int GetHashTablePos(char *lpszString, MPQHASHTABLE *lpTable, int nTableSize)

{
const int HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
int nHash = HashString(lpszString, HASH_OFFSET);
int nHashA = HashString(lpszString, HASH_A);
int nHashB = HashString(lpszString, HASH_B);
int nHashStart = nHash % nTableSize, nHashPos = nHashStart;
while (lpTable[nHashPos].bExists)
{
if (lpTable[nHashPos].nHashA == nHashA && lpTable[nHashPos].nHashB == nHashB
)
return nHashPos;
else
nHashPos = (nHashPos + 1) % nTableSize;

if (nHashPos == nHashStart)
break;
}
return -1; //Error value
}
1. 计算出字符串的三个哈希值(一个用来确定位置,另外两个用来校验)
2. 察看哈希表中的这个位置
3. 哈希表中这个位置为空吗?如果为空,则肯定该字符串不存在,返回
4. 如果存在,则检查其他两个哈希值是否也匹配,如果匹配,则表示找到了该字符串,返

5. 移到下一个位置,如果已经越界,则表示没有找到,返回
6. 看看是不是又回到了原来的位置,如果是,则返回没找到
7. 回到3
怎么样,很简单的算法吧,但确实是天才的idea, 其实最优秀的算法往往是简单有效的算法.

來自:Ngacn.com  

 

Re:Blizzard的MPQ文件格式搜索算法

晕死,其实这篇文章最早还是我在bokee.com上写的,转来转去哪儿都有了 🙂

不过这篇文章现在看起来已经很土了,而且还有一些观点是不妥的,正好纠正一下

1。解决hash表碰撞有很多方法,最开始提到的链表(chaining)是其中一种,这种方法并不是我原先认为的“糟糕”的方法,相反,这种方法是最普遍的,C++标准库中的hash表用的正是这种方法。

2. 暴雪没有使用链表,而是使用线性挖掘方式(Linear probing),这是由于这种不需要动态分配内存,而且更方便将数据序列化到磁盘文件上。

2. 更好的方法是"幂次挖掘"方法(quadratic probing),发生碰撞时,按照"+1,-1,+4,-4,+9,-9,...,+n^2,-n^2"方式移动,这种方式下还需要要求容器的长度是质数,可以达到更快的速度

3. 这些方法都不是什么秘密,稍微详细一些的数据结构课程里都有,所以有一点可以肯定,上课认真听讲是没有坏处的

4. 最后是一个好消息,2008 C++标准里已经有hash表了,只不过换了一个官方名称"unordered",有点怪哈

发表在 article | 标签为 | 用HASH表进行海量数据搜索已关闭评论

海量数据之哈希

 

适用范围:快速查找,删除的基本数据结构,通常需要总数据量可以放入内存

基本原理及要点:

hash函数选择,针对字符串,整数,排列,具体相应的hash方法。

碰撞处理,一种是open hashing,也称为拉链法;另一种就是closed hashing,也称开地址法,opened addressing。

(1)开放定址法

hi=(h(key)+di) mod m i=1,2,...,k(k<=m-1)

其中m为表长,di为增量序列

如果di值可能为1,2,3,...m-1,称线性探测再散列。

如果di取值可能为1,-1,2,-2,4,-4,9,-9,16,-16,...k*k,-k*k(k<=m/2)

称二次探测再散列。

如果di取值可能为伪随机数列。称伪随机探测再散列。开放地址法堆装填因子的要求

开放定址法要求散列表的装填因子α≤l,实用中取α为0.5到0.9之间的某个值为宜。

(2)二次探查法(quadratic probing)

二次探查法的探查序列是:

hi=(h(key)+i*i)%m 0≤i≤m-1 //即di=i2

即探查序列为d=h(key),d+12,d+22,…,等。

该方法的缺陷是不易探查到整个散列空间。

(3)双重散列法(double hashing)

该方法是开放定址法中最好的方法之一,它的探查序列是:

hi=(h(key)+i*h1(key))%m 0≤i≤m-1 //即di=i*h1(key)

即探查序列为:

d=h(key),(d+h1(key))%m,(d+2h1(key))%m,…,等。

该方法使用了两个散列函数h(key)和h1(key),故也称为双散列函数探查法。

(4)拉链法

拉链法解决冲突的做法是:将所有关键字为同义词的结点链接在同一个单链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组t[0..m-1]。凡是散列地址为i的结点,均插入到以t为头指针的单链表中。t中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于1,但一般均取α≤1。

(5)建立一个公共溢出区

假设哈希函数的值域为[0,m-1],则设向量hashtable[0..m-1]为基本表,另外设立存储空间向量overtable[0..v]用以存储发生冲突的记录。


扩展:

d-left hashing
中的d是多个的意思,我们先简化这个问题,看一看2-left hashing。2-left hashing指的是将一个哈希表分成长度相等的两半,分别叫做T1和T2,给T1和T2分别配备一个哈希函数,h1和h2。在存储一个新的key时,同 时用两个哈希函数进行计算,得出两个地址h1[key]和h2[key]。这时需要检查T1中的h1[key]位置和T2中的h2[key]位置,哪一个 位置已经存储的(有碰撞的)key比较多,然后将新key存储在负载少的位置。如果两边一样多,比如两个位置都为空或者都存储了一个key,就把新key 存储在左边的T1子表中,2-left也由此而来。在查找一个key时,必须进行两次hash,同时查找两个位置。


问题实例:

1).海量日志数据,提取出某日访问百度次数最多的那个IP。


IP的数目还是有限的,最多2^32个,所以可以考虑使用hash将ip直接存入内存,然后进行统计。

发表在 article | 标签为 | 海量数据之哈希已关闭评论