omiga

简单就好

LevenshTeinDistance算法的JavaScript实现

发表评论»

LevenshTeinDistance是俄罗斯科学家Vladimir Levenshtein在1965年提出的根据编辑距离(Edit Distance)计算字符串相似度的一种算法。

/*
 * @name:LevenshteinDistance.js
 * @description:
 * @author:wondger@gmail.com
 * @date:2012-04-17
 * @param:
 * @todo:
 * @changelog:
 */
var LevenshteinDistance = {
    _str1:null,
    _str3:null,
    _matrix:null,
    _isString:function(s){
        return Object.prototype.toString.call(s) === '[object String]';
    },
    _isNumber:function(s){
        return Object.prototype.toString.call(s) === '[object Number]';
    },
    init:function(str1,str2){
        if(!this._isString(str1) || !this._isString(str2)) return;

        this._str1 = str1;
        this._str2 = str2;

        str1.length &&  str2.length && this._createMatrix(str1.length+1,str2.length+1);
        this._matrix && this._initMatrix();

        return this;
    },
    get:function(){
        return 1 - this._getDistance()/Math.max(this._str1.length,this._str2.length);
    },
    //计算编辑距离
    _getDistance:function(){
        var len1 = this._str1.length,
            len2 = this._str2.length;

        if(!len1 || !len2) return Math.max(len1,len2);

        var str1 = this._str1.split(''),
            str2 = this._str2.split('');

        var i = 0,j = 0,temp = 0;
        while(i++ < len1){
            j = 0;
            while(j++ < len2){
                 temp = str1[i-1] === str2[j-1] ? 0 : 1;
                 this._matrix[i][j] = Math.min(this._matrix[i-1][j]+1,this._matrix[i][j-1]+1,this._matrix[i-1][j-1]+temp);
             }
         }
         return this._matrix[i-1][j-1];
     },
     /*
      * 初始化矩阵
      * 为第一行、第一列赋值
      */
     _initMatrix:function(){
         var cols = this._matrix[0].length,
             rows = this._matrix.length;
         var l = Math.max(cols,rows);
         while(l--){
             cols-1 >= l && (this._matrix[0][l] = l);
             rows-1 >= l && (this._matrix[l][0] = l);
        }
    },
    /*
     * 创建矩阵
     * n:行
     * m:列
     */
    _createMatrix:function(n,m){
        if(!this._isNumber(n) || !this._isNumber(m) || n<1 || m<1) return;

        this._matrix = new Array(n),i = 0;
        while(i<n) this._matrix[i++] = new Array(m);
    }
}

示例:

alert(LevenshteinDistance.init('omiga.org','omiga').get()); // 0.5555555555555556
alert(LevenshteinDistance.init('omiga','omiga').get()); // 1 完全相同
alert(LevenshteinDistance.init('god','superman').get()); // 0 完全不同

自定义事件

发表评论»

对于一个事件通常我们主要关注两件事情:

  1. 怎么注册/注销
  2. 何时触发

DOM Level 2 EventsDOM Level 3 Events中已经提供了接口用于对自定义事件的支持,addEventListener/removeEventListener完成对任意事件函数的注册/注销(标准事件、自定义事件),createEvent-initEvent-dispatchEvent完成事件的触发。

注册/注销方式和普通标准事件没有区别,而事件的触发需要自行再包装实现一下,这个方法我们也暂命名为dispatchEvent。

var Event = {
    dispatchEvent:function(el,type,evtType){
        //create Event
        var evtType = evtType || 'CustomEvent',
            evt = document.createEvent(evtType);
        //init Event
        evt.initEvent(type,true,true);
        //dispatch Event
        el.dispatchEvent(evt);
    }
}

createEvent支持多种事件类型丰富,比如"UIEvents""MouseEvents""MutationEvents""HTMLEvents",具体类型可参考前面的两个文档。不同类型事件具有不同的初始化方法,比如"initUIEvent""initMouseEvent""initMutationEvent""initHTMLEvent"…使用专有初始化方法具有更多大灵活性,具有更多的参数接口。而"initEvent"是一个基础方法,使用起来更简单,但有时候无法满足更多的需求。

IE9及以后版本开始支持dispatchEvent,而IE8及以前版本并不支持。但好在IE提供了另外一个方法fireEvent用于触发事件函数,而且标准事件模型中的createEvent-initEvent-dispatchEvent过程在IE中只需要createEventObject-fireEvent两个步骤即可完成,当然其实是将initEvent中的初始化工作合并到了createEventObject中。所以我们也有了IE8及以下版本的fireEvent方法实现。

var Event = {
    fireEvent:function(el,type,cfg){
        //create Event
        var evt = document.createEventObject(cfg);
        //fire Event
        el.fireEvent('on'+type,evt);
    }
}

但遗憾的是fireEvent仅能触发通过attachEvent注册的标准事件,对于我们的自定义事件该方法其实形同虚设。

另外:即使对于标准事件,fireEvent还有一个很大的不同:不会触发默认行为。比如有一个form,

Event.dispatchEvent(form,'submit'); //会触发submit行为提交表单
Event.fireEvent(form,'submit'); //不会触发submit行为

对于不支持自定义事件注册/注销、触发的浏览器,可是有如下方案:

  • 注册/注销
    将DOM与自定义事件对应关系保存,这其中涉及到保存的自定义事件与DOM对象的对应关系数据的结构如何设计;以及如何避免重复注册
  • 触发
    对于关系保存下来了,其实触发就很简单,直接调用事件方法即可,唯一需要注意的是一个模拟的Event对象传递个事件函数

代码不贴了~···^-^

参考:

多个github帐号的SSH key切换

2条评论»

github使用SSH与客户端连接。如果是单用户(first),生成密钥对后,将公钥保存至github,每次连接时SSH客户端发送本地私钥(默认~/.ssh/id_rsa)到服务端验证。单用户情况下,连接的服务器上保存的公钥和发送的私钥自然是配对的。但是如果是多用户(first,second),我们在连接到second的帐号时,second保存的是自己的公钥,但是SSH客户端依然发送默认私钥,即first的私钥,那么这个验证自然无法通过。不过,要实现多帐号下的SSH key切换在客户端做一些配置即可。

首先cd到~/.ssh 使用 ssh-keygen -t -rsa -C ‘second@mail.com’ 生成新的SSH key:id_rsa_second,生成完后将新的SSH public key添加到github。

ssh-keygen -t rsa -C 'second@mail.com'

默认SSH只会读取id_rsa,所以为了让SSH识别新的私钥,需要将其添加到SSH agent

ssh-add ~/.ssh/id_rsa_second

该命令如果报错:Could not open a connection to your authentication agent.无法连接到ssh agent,可执行ssh-agent bash命令后再执行ssh-add命令。

完成以上步骤后在~/.ssh目录创建config文件,该文件用于配置私钥对应的服务器。内容如下:

# Default github user(first@mail.com)
Host github.com
 HostName github.com
 User git
 IdentityFile C:/Users/username/.ssh/id_rsa

# second user(second@mail.com)
Host github-second
 HostName github.com
 User git
 IdentityFile C:/Users/username/.ssh/id_rsa_second

阅读全文»

JavaScript中的property和attribute

发表评论»

首先看看这两个单词的英文释义(来自有道词典)。先是property:

property ['prɔpəti]

n. 性质,性能;财产;所有权

英英释义:

  1. any area set aside for a particular purpose “the president was concerned about the property across from the White House”
    同义词:place
  2. something owned; any tangible or intangible possession that is owned by someone “that hat is my property”; ” he is a man of property”
    同义词:belongings | holding | material possession
  3. a basic or essential attribute shared by all members of a class
  4. a construct whereby objects or individuals can be distinguished “self-confidence is not an endearing property”
    同义词:attribute | dimension
  5. any movable articles or objects used on the set of a play or movie
    同义词:prop

重点看2、3、4条。

再看attribute:

attribute [ə'tribju:t, 'ætribju:t]

n. 属性;特质
vt. 归属;把…归于

英英释义:

n.

  1. a construct whereby objects or individuals can be distinguished
    同义词:property | dimension
  2. an abstraction belonging to or characteristic of an entity

v.

  1. attribute or credit to ”We attributed this quotation to Shakespeare”
    同义词:impute | ascribe | assign
  2. decide as to where something belongs in a scheme
    同义词:assign

property,attribute都作“属性”解,但是attribute更强调区别于其他事物的特质/特性,而在这篇文章中也提交到attribute是property的子集

而在JavaScript中,property和attribute更是有明显的区别。众所周知,setAttribute是为DOM节点设置/添加属性的标准方法:

var ele = document.getElementById("my_ele");
ele.setAttribute("title","it's my element");

但很多时候我们也这样写:

ele.title = "it's my element";

如果不出什么意外,他们都运行的很好,它们似乎毫无区别?而且通常情况下我们还想获取到我们设置的“属性”,我们也很爱这样写:

alert(ele.title);

这时候,你便会遇到问题,如果你所设置的属性属于DOM元素本身所具有的标准属性,不管是通过ele.setAttribute还是ele.title的方式设置,都能正常获取。但是如果设置的属性不是标准属性,而是自定义属性呢?

阅读全文»

SSI详解

发表评论»

SSI(Server Side Include)使用在HTML中,用于在请求内容返回到客户端前执行页面中的SSI命令,生成动态内容。通常用于多个页面引用公共的内容模块,将此模块分离出来,使用SSI引入即可。

<!--#include virtual="/inc/header.html"-->

以上代码便能在服务端完成header.html的动态引入,非常简单。

服务端配置

使用SSI之前需要服务端进行简单的配置,开启SSI功能。SSI是针对HTML增加动态内容的技术,所以只对HTML类型文件(.html,.shtml),使用SSI功能的文件建议使用.shtml后缀,便于维护。如果使用.shtml后缀需在服务端作一些配置:

AddType text/html .shtml
AddOutputFilter INCLUDES .shtml

第一行命名配置将.shtml作为html文件返回

第二行命令用于在返回请求内容前执行页面中的SSI命令,如果你在.html文件中使用SSI,那么将.shtml改为.html即可。

SSI命令

SSI的语法有点像HTML注释,所以如果SSI不能识别,那么将被视作HTML注释处理。SSI的语法功能主要包括:变量的设置/获取,文件的引用,可执行命令,条件表达式等。

SSI基本语法

<!--#command param="value"-->

SSI的语法非常简单,但使用中需注意以下几点:

  1. <!–与#之间无空格
  2. SSI大小写敏感
  3. 所有value需写在引号中

config命令

config命令主要用于修改SSI的默认设置,诸如时间格式,默认错误信息,文件大小单位。

设置默认错误信息:errmsg

<!--#config errmsg="Error,please contact webmaster@mail.com"-->

定义日期和时间格式:timefmt

<!--#config timefmt="%A, %B %d, %Y"-->

定义文件大小单位

<!--#config sizefmt="bytes"-->

config命令只对其后使用的命令生效。同时,后定义的设置具有更高的优先级,会覆盖之前的设置。

阅读全文»