首页 > 程序开发 > web前端 > JavaScript >

javascript笔记:String的replace,由正则表达式到jQuery选择器

2011-09-24

 我在上一篇博客里谈到了javascript里面的String类的 replace方法的一些问题,今天我真正的学习了javascript里的正则表达式的用法(以前总是不屑学习这个技术,现在发现编程里字符处理的技术还是相当的重要,应...

 我在上一篇博客里谈到了javascript里面的String类的 replace方法的一些问题,今天我真正的学习了javascript里的正则表达式的用法(以前总是不屑学习这个技术,现在发现编程里字符处理的技术还是相当的重要,应用领域很广泛而且也有一定难度,比如jQuery源码里面就有很多正则表达式的使用),对于String类里 s.replace(regex,function(){})的理解更清晰,以前不清晰的原因是没有学习好正则表达式。我写了下面的测试代码:

//下面代码请在装有firebug的firefox里面运行
function myReplace()
{
var reg = /%[1-4]/g;
var data = "And the %1 want to know whose %2 you %3";

while(1==1)
{
var val = reg.exec(data);
if (val == null)
{
break;
}else{
console.log(val);
}
}

reg = /CJ[0-9]{2}/g;
data = 'CJ9080,CJ8976,CJ12919,CJ8765';
while(1==1)
{
var val = reg.exec(data);
if (val == null)
{
break;
}else{
console.log(val);
}
}

}
myReplace();

结果如下:

\

  其实String类的s.replace(regex,function(){})用法就是了Regex的exec()方法,只不过当正则式为[1-4]这样格式的时候,replace方法会在遍历字符串时候把里面的1-4的值都取出来,放到function的argument[1]里面。

  今天抽时间读了一下jQuery的源代码,jQuery说白了就是一个选择器,例如我们常看到这样的写法:

  

jQuery('#userId').val();
jQuery('div').text();

  

上面代码就是在使用jQuery选择器,jQuery选择器实现了下列四个方法:


jQuery( expression, context )
Returns: jQuery
这个函数接收一个CSS选择器的字符串,然后用这个字符串去匹配一组元素。
This function accepts a string containing a CSS selector which is then used to match a set of elements.
jQuery( html, ownerDocument )
Returns: jQuery
根据HTML原始字符串动态创建Dom元素.
Create DOM elements on-the-fly from the provided String of raw HTML.
jQuery( elements )
Returns: jQuery
将一个或多个Dom对象封装jQuery函数功能(即封装为jQuery包装集)
Wrap jQuery functionality around a single or multiple DOM Element(s).
jQuery( callback )
Returns: jQuery
$(document).ready()的简写方式
A shorthand for $(document).ready().
上面摘选自jQuery官方手册。

在选择器方法里面使用到了这样一个正则表达式:

quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/
这个正则表达式都是在我们传入jQuery里面第一个参数是string时候会调用,具体点就是当你不是传入$(""), $(null), $(undefined)或者$(DOMElement)时候就会使用到这个正则表达式。因此我想在这里好好分析下这两个正则表达式。

首先补充下正则表达式的基础知识:

元字符

描述

.

匹配任何单个字符。例如正则表达式r.t匹配这些字符串:ratrutr t,但是不匹配root

$

匹配行结束符。例如正则表达式weasel$ 能够匹配字符串"He&#39;s a weasel"的末尾
但是不能匹配字符串"They are a bunch of weasels."

^

匹配一行的开始。例如正则表达式^When in能够匹配字符串"When in the course of human events"的开始,但是不能匹配"What and When in the"

*

匹配0或多个正好在它之前的那个字符。例如正则表达式。*意味着能够匹配任意数量的任何字符。

\

这是引用符,用来将这里列出的这些元字符当作普通的字符来进行匹配。例如正则表达式\$被用来匹配美元符号,而不是行尾,类似的,正则表达式\.用来匹配点字符,而不是任何字符的通配符。

[ ]
[c1-c2]
[^c1-c2]

匹配括号中的任何一个字符。例如正则表达式r[aou]t匹配ratrotrut,但是不匹配ret。可以在括号中使用连字符-来指定字符的区间,例如正则表达式[0-9]可以匹配任何数字字符;还可以制定多个区间,例如正则表达式[A-Za-z]可以匹配任何大小写字母。另一个重要的用法是排除,要想匹配除了指定区间之外的字符——也就是所谓的补集——在左边的括号和第一个字符之间使用^字符,例如正则表达式[^269A-Z] 将匹配除了269和所有大写字母之外的任何字符。

\< \>

匹配词(word)的开始(\<)和结束(\>)。例如正则表达式\<the\>能够匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:这个元字符不是所有的软件都支持的。

\( \)

\( \) 之间的表达式定义为group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用\1 \9 的符号来引用。

|

将两个匹配条件进行逻辑Or)运算。例如正则表达式(him|her) 匹配"it belongs to him""it belongs to her",但是不能匹配"it belongs to them."。注意:这个元字符不是所有的软件都支持的。

+

匹配1或多个正好在它之前的那个字符。例如正则表达式9+匹配999999等。注意:这个元字符不是所有的软件都支持的。

?

匹配01个正好在它之前的那个字符。注意:这个元字符不是所有的软件都支持的。

{i}
{i,j}

匹配指定数目的字符,这些字符是在它之前的表达式定义的。例如正则表达式A[0-9]{3} 能够匹配字符"A"后面跟着正好3个数字字符的串,例如A123A348等,但是不匹配A1234。而正则表达式[0-9]{4,6} 匹配连续的任意4个、5个或者6个数字字符。注意:这个元字符不是所有的软件都支持的。

\s

匹配任何空白字符,包括空格、制表符、换页符等等。等价于[?\f\n\r\t\v]

\w

匹配包括下划线的任何单词字符。等价于&rsquo;[A-Za-z0-9_]&lsquo;

\W

匹配任何非单词字符。等价于&lsquo;[^A-Za-z0-9_]&lsquo;

正则表达式quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,可以由| 分为两个部分,前一个部分是^[^<]*(<[\w\W]+>)[^>]*$,这个有开始符号^和结束符号$,该表达式按顺序分析:

1. [^<]*----标示字符的头部可以是除了<的任意字符或者是干脆没有字符

2. (<[\w\W]+>)-----这个表示字符串里要包含用<>包含的字符,例如<p>,<div>等等都是符合要求的

3. [^>]*----字符串尾部是除了>的任意字符或者没有字符

由上可知表达式^[^<]*(<[\w\W]+>)[^>]*$的意思是字符串里面一定要包含被尖括号包含的字符也就是html代码。

正则表达式的后半部分是:^#([\w-]+)$,这个就比较简单了,它的含义是匹配带上#号的任意字符。

那么整个表达式的含义就是匹配HTML标记和ID表达式。下面我做了针对这个表达式的测试,代码如下:

function regrexFtn()

{

var quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/;

var data = "#userId";

console.log(quickExpr.exec(data));

data = "<span>javascript jquery</span>";

console.log(quickExpr.exec(data));

data = "start<span>javascript jquery</span>end";

console.log(quickExpr.exec(data));

data = "div .red";

console.log(quickExpr.exec(data));

data = "javascript jquery";

console.log(quickExpr.exec(data));

data = "div";

console.log(quickExpr.exec(data));

data = ".odd";

console.log(quickExpr.exec(data));

}

regrexFtn();

结果如下:

\

我在读jQuery选择器源码时候,对于这个表达式的正确理解是我的难点,所以我单独研究下这个表达式,现在清楚了它的功能,那么我在读取选择器的源码就简单多了。下面是jquery-1.4.1.js的选择器的源码:

init: function( selector, context ) {
var match, elem, ret, doc;

// Handle $(""), $(null), or $(undefined)
if ( !selector ) {
return this;
}

// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}

// Handle HTML strings
if ( typeof selector === "string" ) {
// Are we dealing with HTML string or an ID?
match = quickExpr.exec( selector );

// Verify a match, and that no context was specified for #id
if ( match && (match[1] || !context) ) {

// HANDLE: $(html) -> $(array)
if ( match[1] ) {
doc = (context ? context.ownerDocument || context : document);

// If a single string is passed in and it&#39;s a single tag
// just do a createElement and skip the rest
ret = rsingleTag.exec( selector );

if ( ret ) {
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery.fn.attr.call( selector, context, true );

} else {
selector = [ doc.createElement( ret[1] ) ];
}

} else {
ret = buildFragment( [ match[1] ], [ doc ] );
selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
}

// HANDLE: $("#id")
} else {
elem = document.getElementById( match[2] );

if ( elem ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}

// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}

this.context = document;
this.selector = selector;
return this;
}

// HANDLE: $("TAG")
} else if ( !context && /^\w+$/.test( selector ) ) {
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName( selector );

// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return (context || rootjQuery).find( selector );

// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return jQuery( context ).find( selector );
}

// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}

if (selector.selector !== undefined) {
this.selector = selector.selector;
this.context = selector.context;
}

return jQuery.isArray( selector ) ?
this.setArray( selector ) :
jQuery.makeArray( selector, this );
},
源码解析:

参数说明:selector:选择器的符号,可以是任意数据类型。

Context:上下文,指定在文档DOM中那个节点下进行查询,默认值是document

1. 如果我们写的选择器是这样jQuery (""),jQuery (null), jQuery (undefined),那么执行的代码是:


if ( !selector ) {

return this;

}


直接返回一个jQuery对象。


2. 如果我们写的选择器是jQuery(document.getElementById(&#39;#d01&#39;));也就是jQuery里的参数是一个DOM元素,那么执行的代码是:

if ( selector.nodeType ) {
this.context = this[0] = selector;//把当前的DOM元素存入到jQuery类的数组中
this.length = 1;//设置jQuery类的数组长度,方便以后遍历访问
return this;//返回jQuery对象
}
3. 如果我们在jQuery选择器里面传入的是字符串,就是这样的形式jQuery(&#39;..&#39;),那么jQuery都会执行这段代码:

if ( typeof selector === "string" ) {
// Are we dealing with HTML string or an ID?
match = quickExpr.exec( selector );
下面代码如何运行都是根据match这个变量所决定的,根据我上面测试的结果来看看这段代码。

4.jQuery(&#39;#userIds&#39;),jQuery里面的参数是一个ID值,match = quickExpr.exec( selector );的执行结果是:


那么if ( match && (match[1] || !context) )里面的match && (match[1] || !context)等价于(true && (false || true))结果就是false了。接下来执行的代码是:


} else {
elem = document.getElementById( match[2] );//获取DOM元素

if ( elem ) {
//获取该元素确保元素存在,因为在ie或是Opera
//浏览器里面这个方法可能是根据name而不是ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}

//否则就将elem放入jQuery类的数组里,直接返回jQuery对象s
this.length = 1;// 设置jQuery类的数组长度,方便以后遍历访问

this[0] = elem;// 把当前的DOM元素存入到jQuery类的数组中
}

this.context = document;//设置jQuery对象的上下文属性
this.selector = selector;
return this;//返回jQuery对象s
}

5. jQuery(&lsquo;div&rsquo;),当jQuery参数是html标签,那么match = quickExpr.exec( selector );执行的结果就是null了,这时候程序会执行下面代码:

} else if ( !context && /^\w+$/.test( selector ) ) {//正则表达式是检测传入参数是不是符合标签规则的字符串
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName( selector );
}
然后代码会走到这里:
else {
return jQuery( context ).find( selector );
}
但是这时候程序并没有跳出代码,而是走到了

return jQuery.isArray( selector ) ?
this.setArray( selector ) :
jQuery.makeArray( selector, this );
这个蛮奇怪的。

6. 如果jQuery选择器这么写jQuery(&#39;start<span>javascript jquery</span>end&#39;)或者jQuery(&#39;<span>javascript jquery</span>s&#39;),match = quickExpr.exec( selector );执行的结果如下:

\


程序执行的代码是:

if ( match[1] ) {
doc = (context ? context.ownerDocument || context : document);
ret = rsingleTag.exec( selector );

if ( ret ) {
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery.fn.attr.call( selector, context, true );

} else {
selector = [ doc.createElement( ret[1] ) ];
}

} else {
ret = buildFragment( [ match[1] ], [ doc ] );
selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
}
这段代码里操作的都是match[1],可以看出,这里使用到的结果是<span>javascript jquery</span>,也就是代码只是对html代码进行操作。

7. 当我们写这样的选择器时候jQuery(&#39;div .red&#39;),这时候match = quickExpr.exec( selector );执行的结果是null,代码最终会执行到:

quickExpr.exec( selector );执行的结果是null,代码最终会执行到:
} else if ( !context || context.jquery ) {
return (context || rootjQuery).find( selector );//默认调用document.find()方法。

作者“sharpxiajun”

相关文章
最新文章
热点推荐