sizzle分析记录:词法分析器(tokenize)

简介:

词法分析器(tokenize)?

词法分析器又称扫描器。词法分析是指将我们编写的文本代码流解析为一个一个的记号,分析得到的记号以供后续语法分析使用。

 

sizzle引入了tokenize这个概念,意义?

jQuery的选择器,实现了css1-css3的API,但是ECMAScript低版本的API中本身没有针对这种CSS的处理API,在IE8以上就引入了querySelectorAll

各种浏览器实现还有差异,这里不是主题,我们看如果是低版本的接口要如果处理复杂的CSS选择器

首先面临的就是要对复杂的选择器进行分解

例如:

div > div.Aaron p span.red

只能针对每个版本的浏览器的支持力度去匹配各自的选择

所以此时会引入一个词法分析器(tokenize)用来把用户复杂的匹配选择,分解成各自的单元,可以提供给后面对应的接口处理

 


选择器总的来说分四大类:

并联就是合并分组,用逗号分隔

简单的选择器,ID,TAG,CLASS,ATTR,*

关系选择器:> ,+ , ~, 空格

伪类:动作伪类,目标伪类,语言伪类,状态伪类,结构伪类,取反伪类

 

 

Sizzle的Token格式如下 :

复制代码
{
   value:'匹配到的字符串', 
   type:'对应的Token类型',
   matches:'正则匹配到的一个结构'

}
复制代码

 

tokenize需要解析的几种情况:

情况一:多重选择器分组

soFar :$("div, span, p.myClass" )

在出现逗号分隔符的时候,就说明选择所有指定的选择器的组合结果,所以需要分割成各自的处理模块

这种事情当然交给正则来干是最合适的

常规的思路先是通过split(,)先把选择器劈成三部分,然后依次处理各自的模块

 

jQuery对于过滤正则都有一个特点,就是都是元字符^开头,开限制匹配的初始,所以tokenize也是从左边开始一层一层的剥离

rcomma.exec( soFar )) 

var whitespace = "[\\x20\\t\\r\\n\\f]";
var rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" )

匹配第一个出现的非显示字符

换句话匹配

, span, p.myClass

然后在划分容器

复制代码
if ( !matched || (match = rcomma.exec( soFar )) ) {
    if ( match ) {
        // Don't consume trailing commas as valid
        soFar = soFar.slice( match[0].length ) || soFar;
    }
    groups.push( (tokens = []) );
}
复制代码

其结果就是:(结构不合理,先理解这个意思)

groups:[
      tokens :{div, span},
      tokens :{p.myClass}
]

 


情况二:关系处理器分组

在层级关系中有几种特殊的划分 Token : >, +, 空格, ~ 用来表明父与子,兄弟,祖辈子孙之间的层级关系

$( "ul.topnav > li" )

从 > 划分

rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),

可以是>+~或者空白

这个分组是为了之后的关系选择确定

复制代码
if ( (match = rcombinators.exec( soFar )) ) {
    matched = match.shift();
    tokens.push({
        value: matched,
        // Cast descendant combinators to space
        type: match[0].replace( rtrim, " " )
    });
    soFar = soFar.slice( matched.length );
}
复制代码

 


剩余几种Token :

Expr.filter :TAG, ID, CLASS, ATTR, CHILD, PSEUDO

通过一系列的正则抽出表达式中的内容

ID:

///^#((?:\\.|[\w-] | [^\x00-\xa0] ) +)/
var characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+";
var ID = new RegExp("^#(" + characterEncoding + ")")
console.log(ID.exec("#div > li"))  //["#div", "div", index: 0, input: "#div > li"]

 

TAG:

var TAG =  new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" );
console.log(TAG.exec("li > sadf.da dsf"))  //["#div", "div", index: 0, input: "#div > li"]

 

CLASS:

var Class = new RegExp( "^\\.(" + characterEncoding + ")" );
console.log(Class.exec(".li > sadf.da dsf"))

 

ATTR:

属性选择器有点复杂,通过第一次正则只能匹配器出整体,所以需要第二次分解,引入了Expr.preFilter

Expr.preFilter保留了3个兼容处理分别是ATTR,CHILD,PSEUDO复杂的选择器

复制代码
var identifier = characterEncoding.replace( "w", "w#" );
var attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
    // Operator (capture 2)
    "*([*^$|!~]?=)" + whitespace +
    // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
    "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
    "*\\]";

var ATTR = new RegExp( "^" + attributes );

console.log(ATTR.exec("[name*='man']")
复制代码

preFilter:

复制代码
preFilter: {
    "ATTR": function( match ) {
        match[1] = match[1].replace( runescape, funescape );

        // Move the given value to match[3] whether quoted or unquoted
        match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );

        if ( match[2] === "~=" ) {
            match[3] = " " + match[3] + " ";
        }

        return match.slice( 0, 4 );
    },
复制代码

 

本文转自艾伦 Aaron博客园博客,原文链接:http://www.cnblogs.com/aaronjs/p/3842352.html,如需转载请自行联系原作者

相关文章
|
5月前
编译原理——构造预测分析表(判断某字符串是否是文法G(E)的句子)
编译原理——构造预测分析表(判断某字符串是否是文法G(E)的句子)
50 0
|
5月前
|
SQL 关系型数据库 MySQL
Mysql查询语句的书写顺序
这是一个关于SQL查询语句的摘要,主要包括:`SELECT`(可选`DISTINCT`)字段从表1,可连接到表2,带`JOIN`和`ON`条件,`WHERE`过滤条件,`GROUP BY`按字段分组,`HAVING`进一步过滤,`ORDER BY`排序,及`LIMIT`指定返回结果的起始位置和数量。
22 0
|
JavaScript 前端开发 Java
JS中和java语法相近的用法和语句
JS中和java语法相近的用法和语句
74 1
|
Python
巧用for循环嵌套结构
巧用for循环嵌套结构
88 0
|
编译器 C++
C++ 如何去注释语法解析
C++ 如何去注释语法解析
|
前端开发
前端学习案例9-正则-非捕获反向引用
前端学习案例9-正则-非捕获反向引用
60 0
前端学习案例9-正则-非捕获反向引用
|
编译器 C++
C++ 基础篇c++注释语法解析
程序的注释是解释性语句,您可以在 C++ 代码中包含注释,这将提高源代码的可读性。所有的编程语言都允许某种形式的注释。
|
程序员 编译器 Python
Python语法元素分析
Python语法元素分析
106 0