jQuery技术内幕:深入解析jQuery架构设计与实现原理. 3.4 Sizzle( selector, context, results, seed )

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

3.4 Sizzle( selector, context, results, seed )

函数Sizzle( selector, context, results, seed )用于查找与选择器表达式selector匹配的元素集合。该函数是选择器引擎的入口。

函数Sizzle( selector, context, results, seed )执行的6个关键步骤如下:

1)解析块表达式和块间关系符。

2)如果存在位置伪类,则从左向右查找:

a.?查找第一个块表达式匹配的元素集合,得到第一个上下文元素集合。

b.?遍历剩余的块表达式和块间关系符,不断缩小上下文元素集合。

3)否则从右向左查找:

a.?查找最后一个块表达式匹配的元素集合,得到候选集、映射集。

b.?遍历剩余的块表达式和块间关系符,对映射集执行块间关系过滤。

4)根据映射集筛选候选集,将最终匹配的元素放入结果集。

5)如果存在并列选择器表达式,则递归调用Sizzle( selector, context, results, seed )查找匹配的元素集合,并合并、排序、去重。

6)最后返回结果集。

下面来看看该函数的源码实现。

1.?定义Sizzle( selector, context, results, seed )

相关代码如下所示:

3879 var Sizzle = function( selector, context, results, seed ) {

第3879行:定义函数Sizzle( selector, context, results, seed ),接受4个参数:

参数selector:CSS选择器表达式。

参数context:DOM元素或文档对象,作为查找元素的上下文,用于限定查找范围。默认值是当前文档对象。

参数results:可选的数组或类数组,函数Sizzle( selector, context, results, seed )将把查找到的元素添加到其中。

参数seed:可选的元素集合,函数Sizzle( selector, context, results, seed )将从该元素集合中过滤出匹配选择器表达式的元素集合。

2.?修正参数results、context

相关代码如下所示:

3880     results = results || [];

3881     context = context || document;

3882

3883     var origContext = context;

3884

3885     if ( context.nodeType !== 1 && context.nodeType !== 9 ) {

3886         return [];

3887     }

3888    

3889     if ( !selector || typeof selector !== "string" ) {

3890         return results;

3891     }

3892

第3880行:如果未传入参数results,则默认为空数组[]。方法.find( selector )调用Sizzle ( selector, context, results, seed )时会传入一个jQuery对象,匹配元素将会被添加到传入的jQuery对象中。

第3881行:如果未传入参数context,则默认为当前document对象。

第3883行:备份上下文context。因为如果参数selector是以#id开头的,可能会把上下文修正为#id所匹配的元素。这里备份的origContext用于存在并列选择器表达式的情况。

第3885~3887行:如果参数context不是元素,也不是document对象,则忽略本次查询,直接返回空数组[]。

第3889~3891行:如果参数selector是空字符串,或者不是字符串,则忽略本次查询,直接返回传入的参数results。

3.?定义局部变量

相关代码如下所示:

3893     var m, set, checkSet, extra, ret, cur, pop, i,

3894         prune = true,

3895         contextXML = Sizzle.isXML( context ),

3896         parts = [],

3897         soFar = selector;

3898    

第3893~3897行:定义一组局部变量,它们的含义和用途如下:

变量m:用于存放正则chunker每次匹配选择器表达式selector的结果。

变量set:在从右向左的查找方式中,变量set称为“候选集”,是最后一个块表达式匹配的元素集合,其他块表达式和块间关系符则会对候选集set进行过滤;对于从左向右的查找方式,变量set是当前块表达式匹配的元素集合,也是下一个块表达式的上下文。

变量checkSet:对于从右向左的查找方式,变量checkSet称为“映射集”,其初始值是候选集set的副本,其他块表达式和块间关系符则会对映射集checkSet进行过滤,过滤时先根据块间关系符将其中的元素替换为父元素、祖先元素或兄弟元素,然后把与块表达式不匹配的元素替换为false,最后根据映射集checkSet筛选候选集set;对于从右向左的查找方式,事实上在查找过程中并不涉及变量checkSet,只是在函数Sizzle()的最后为了统一筛选和合并匹配元素的代码,将变量checkSet与变量set指向了同一个数组。

变量extra:用于存储选择器表达式中第一个逗号之后的其他并列选择器表达式。如果存在并列选择器表达式,则会递归调用函数Sizzle( selector, context, results, seed )查找匹配元素集合,并执行合并、排序和去重操作。

变量ret:只在从右向左执行方式中用到,用于存放查找器Sizzle.find( expr, context, isXML )对最后一个块表达式的查找结果,格式为{ expr:“...”, set: array }。

变量pop:只在从右向左的查找方式中用到,表示单个块表达式。

变量prune:只在从右向左的查找方式中用到,表示候选集set是否需要筛选,默认为true,表示需要筛选,如果选择器表达式中只有一个块表达式,则变量prune为false。

变量contextXML:表示上下文context是否是XML文档。

变量parts:存放了正则chunker从选择器表达式中提取的块表达式和块间关系符。

变量soFar:用于保存正则chunker每次从选择器表达式中提取了块表达式或块间关系符后的剩余部分,初始值为完整的选择器表达式。

4.?解析块表达式和块间关系符

相关代码如下所示:

3860 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,

 

3899     // Reset the position of the chunker regexp (start from head)

3900     do {

3901         chunker.exec( "" );

3902         m = chunker.exec( soFar );

3903

3904         if ( m ) {

3905             soFar = m[3];

3906        

3907             parts.push( m[1] );

3908        

3909             if ( m[2] ) {

3910                 extra = m[3];

3911                 break;

3912             }

3913         }

3914     } while ( m );

3915

第3900~3914行:用正则chunker从选择器表达式中提取块表达式和块间关系符,直到全部提取完毕或遇到下一个并列选择器表达式为止。正则chunker称为“分割器”,含有3个分组:块表达式或块间关系符、逗号、选择器表达式剩余部分,这也是Sizzle中最长、最复杂、最关键的正则,具体将在3.5节单独介绍和分析。

第3901~3902行:正则chunker每次匹配选择器表达式的剩余部分之前,先通过匹配一个空字符来重置正则chunker的开始匹配位置,从而使得每次匹配时都会从头开始匹配。直接设置“chunker.lastIndex = 0;”也能达到同样的效果。

第3904~3913行:如果正则chunker可以匹配选择器表达式的剩余部分,则将第三个分组(即经过当前匹配后的剩余部分)赋予变量soFar,下次do-while循环时继续匹配;通过这种方式也可过滤掉一些垃圾字符(如空格);同时,将第一个分组中的块表达式或块间关系符插入数组parts中;此外,如果第二个分组不是空字符串,即遇到了逗号,表示接下来是一个并列选择器表达式,则将第三个分组保存在变量extra,然后结束循环。

5.?如果存在位置伪类,则从左向右查找

相关代码如下所示:

3916     if ( parts.length > 1 && origPOS.exec( selector ) ) {

3917

3918         if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {

3919             set = posProcess( parts[0] + parts[1], context, seed );

3920

3921         } else {

3922            set = Expr.relative[ parts[0] ] ?

3923                [ context ] :

3924                Sizzle( parts.shift(), context );

3925

3926             while ( parts.length ) {

3927                selector = parts.shift();

3928

3929                if ( Expr.relative[ selector ] ) {

3930                    selector += parts.shift();

3931                 }

3932                

3933                set = posProcess( selector, set, seed );

3934             }

3935         }

3936

 

4221 var Expr = Sizzle.selectors = {

4224     match: {

4231         POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,

4233     },

4749 };

4751 var origPOS = Expr.match.POS,

第3916~3935行:如果存在块间关系符(即相邻的块表达式之间有依赖关系)和位置伪类,例如,$('div button:first'),则从左向右查找。正则origPOS中定义了所支持的位置伪类,见第4231行。

为什么遇到位置伪类需要从左向右查找呢?以$( "div button:first" )为例,在查找所有div元素下的所有button元素中的第一个时,位置伪类":first"过滤的是"div button"匹配的元素集合,因此,必须从左向右查找,并且需要先从选择器表达式中删除位置伪类,然后执行查找,最后才用位置伪类过滤查找结果。这个过程由函数posProcess( selector, context, seed )实现。

第3918~3919行:如果数组parts中只有两个元素,并且第一个是块间关系符,则可以直接调用函数posProcess( selector, context, seed )查找匹配的元素集合。

第3921~3935行:否则,从左向右对数组parts中的其他块表达式逐个进行查找,每次查找时指定前一个块表达式匹配的元素集合作为上下文,即不断缩小查找范围。

第3922~3924行:首先,从数组parts头部弹出第一个块表达式,递归调用函数Sizzle( selector, context, results, seed )查找匹配元素集合,得到第一个上下文元素集合;如果数组parts的第一个元素是块间关系符,则直接把参数context作为第一个上下文元素集合。

第3926~3934行:从左向右遍历数组parts中的其他块表达式和块间关系符,调用函数posProcess( selector, context, seed )查找匹配元素集合,调用时传入的参数selector含有一个块间关系符和一个块表达式,并且指定上下文为前一个块表达式匹配的元素集合set,调用后再将返回值赋值给变量set,作为下一个块表达式的上下文。

posProcess( selector, context, seed )

函数posProcess( selector, context, seed )在指定的上下文数组context下,查找与选择器表达式selector匹配的元素集合,并且支持位置伪类。选择器表达式selector由一个块间关系符和一个块表达式组成。

函数posProcess( selector, context, seed )执行的3个关键步骤如下:

1)删除选择器表达式中的所有伪类。

2)调用Sizzle( selector, context, results, seed )查找删除伪类后的选择器表达式所匹配的元素集合。

3)调用 Sizzle.filter( expr, set, inplace, not )用伪类过滤查找结果。

下面来看看该函数的源码实现。相关代码如下所示:

5266 var posProcess = function( selector, context, seed ) {

5267     var match,

5268        tmpSet = [],

5269        later = "",

5270        root = context.nodeType ? [context] : context;

5271

5272     // Position selectors must be done after the filter

5273     // And so must :not(positional) so we move all PSEUDOs to the end

5274     while ( (match = Expr.match.PSEUDO.exec( selector )) ) {

5275        later += match[0];

5276        selector = selector.replace( Expr.match.PSEUDO, "" );

5277     }

5278

5279     selector = Expr.relative[selector] ? selector + "*" : selector;

5280

5281     for ( var i = 0, l = root.length; i < l; i++ ) {

5282        Sizzle( selector, root[i], tmpSet, seed );

5283     }

5284

5285     return Sizzle.filter( later, tmpSet );

5286 };

第5274~5277行:删除选择器表达式中的所有伪类,并累计在变量 later 中。

第5279行:如果删除伪类后的选择器表达式只剩一个块间关系符,则追加一个通配符"*"。

第5281~5283行:遍历上下文数组,调用函数Sizzle( selector, context, results, seed )查找删除伪类后的选择器表达式匹配的元素集合,将查找结果合并到数组tmpSet 中。

第5285行:调用方法Sizzle.filter( expr, set, inplace, not )用记录的伪类later 过滤元素集合tmpSet,并返回一个新数组,其中只包含了过滤后的元素。

下面回到对函数Sizzle( selector, context, results, seed )的分析中。

6.?如果不存在位置伪类,则从右向左查找

(1)尝试缩小查找范围

相关代码如下所示:

3937     } else {

3938         // Take a shortcut and set the context if the root selector is an ID

3939         // (but not if it'll be faster if the inner selector is an ID)

3940         if ( !seed && parts.length > 1 &&

                    context.nodeType === 9 &&

                    !contextXML &&

3941                Expr.match.ID.test(parts[0]) &&

                    !Expr.match.ID.test(parts[parts.length - 1]) ) {

3942

3943             ret = Sizzle.find( parts.shift(), context, contextXML );

3944             context = ret.expr ?

3945                Sizzle.filter( ret.expr, ret.set )[0] :

3946                ret.set[0];

3947         }

3948

3949         if ( context ) {

                 // 省略从右向左查找的代码

3982         } else {

3983             checkSet = parts = [];

3984         }

3985     }

3986

第3940~3947行:如果第一个块选择器是 ID 类型(即格式为#id),并且最后一个块选择器不是ID 类型,则修正上下文 context 为第一个块选择器匹配的元素,以缩小查找范围,提高查找效率。在这个过程中,先调用方法 Sizzle.find( expr, context, isXML ) 对第一个块表达式执行简单的查找,如果还有剩余部分,再调用方法 Sizzle.filter( expr, set, inplace, not ) 对查找结果进行过滤,最后取匹配元素集合的第一个元素作为后续查找的上下文。

第3982~3984行:如果第一个块表达式是ID类型,但是没有找到匹配的元素,则没有继续查找和过滤的必要了,此时直接清空数组parts,并设置映射集为空数组。

(2)查找最后一个块表达式匹配的元素集合,得到候选集set、映射集checkSet

相关代码如下所示:

3949         if ( context ) {

3950             ret = seed ?

3951                 { expr: parts.pop(), set: makeArray(seed) } :

3952                 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );

3953

3954             set = ret.expr ?

3955                 Sizzle.filter( ret.expr, ret.set ) :

3956                 ret.set;

3957

3958             if ( parts.length > 0 ) {

3959                 checkSet = makeArray( set );

3960

3961             } else {

3962                 prune = false;

3963             }

3964

第3950~3956行:查找最后一个块表达式匹配的元素集合,得到候选集 set。先调用方法Sizzle.find( expr, context, isXML )对最后一个块表达式执行简单的查找,如果还有剩余部分,再调用方法Sizzle.filter( expr, set, inplace, not )对查找结果进行过滤。

如果传入了参数seed,则不需要调用Sizzle.find()查找,只调用Sizzle.filter()过滤。

第3958~3963行:如果数组parts中还有其他元素,即还有块表达式或块间关系符,则创建一份候选集set的副本,并赋值给checkSet,作为映射集;如果数组parts为空,则表示选择器表达式中只有一个块表达式,此时设置变量prune为false,表示不需要对候选集set进行筛选。

(3)遍历剩余的块表达式和块间关系符,对映射集checkSet执行块间关系过滤

相关代码如下所示:

3965             while ( parts.length ) {

3966                cur = parts.pop();

3967                pop = cur;

3968

3969                if ( !Expr.relative[ cur ] ) {

3970                    cur = "";

3971                } else {

3972                    pop = parts.pop();

3973                }

3974

3975                if ( pop == null ) {

3976                    pop = context;

3977                 }

3978

3979                 Expr.relative[ cur ]( checkSet, pop, contextXML );

3980             }

3981

第3965~3980行:从右向左遍历数组 parts 中剩余的块表达式和块间关系符,调用块间关系符在 Sizzle.selectors.relative 中对应的过滤函数,对映射集 checkSet 执行块间关系过滤,直至数组 parts 为空为止。

第3966~3973行:变量 cur 表示块间关系符,变量pop 表示块间关系符左侧的块表达式。每次遍历时,如果弹出的元素不是块间关系符,则默认为后代关系符;如果弹出的元素是块间关系符,则再弹出一个作为块表达式。因为是从右向左查找,所以变量 pop 的作用是作为过滤映射集checkSet 的上下文。

第3975~3977行:如果仍然未找到前一个块表达式 pop,则表示已经到达数组头部,直接将上下文context 作为映射集checkSet 的上下文。

第3979行:块间关系过滤函数的参数格式为:

Sizzle.selectors.relative[ 块间关系符 cur ]( 映射集 checkSet, 左侧块表达式 pop, contextXML );

在块间关系过滤函数中,会先根据块间关系符cur的类型将映射集checkSet的元素替换为父元素、祖先元素或兄弟元素,然后将与左侧块表达式pop不匹配的元素替换为false,具体请参见3.8节。

7.?根据映射集checkSet筛选候选集set,将最终的匹配元素放入结果集results

相关代码如下所示:

3987     if ( !checkSet ) {

3988         checkSet = set;

3989     }

3990

3991     if ( !checkSet ) {

3992         Sizzle.error( cur || selector );

3993     }

3994

3995     if ( toString.call(checkSet) === "[object Array]" ) {

3996         if ( !prune ) {

3997             results.push.apply( results, checkSet );

3998

3999         } else if ( context && context.nodeType === 1 ) {

4000             for ( i = 0; checkSet[i] != null; i++ ) {

4001                 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {

4002                     results.push( set[i] );

4003                 }

4004             }

4005

4006         } else {

4007             for ( i = 0; checkSet[i] != null; i++ ) {

4008                 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {

4009                     results.push( set[i] );

4010                 }

4011             }

4012         }

4013

4014     } else {

4015         makeArray( checkSet, results );

4016     }

4017

第3987~3989行:在前面查找匹配元素集合的过程中,如果是从左向右查找的,不会涉及映射集 checkSet;如果是从右向左查找的,且只有一个块表达式,也不会对于映射集 checkSet 赋值。在这两种情况下,为了统一筛选和合并匹配元素的代码,在这里要先设置映射集 checkSet 和候选集set 指向同一个数组。

第3995~4012行:如果映射集 checkSet 是数组,则遍历映射集checkSet,检查其中的元素是否满足匹配条件,如果满足,则将候选集set 中对应的元素放入结果集results。

第3996~3997行:如果变量 prune 为false,表示不需要筛选候选集set,则直接将映射集checkSet 插入结果集results 中。注意这里的隐藏逻辑:当选择器表达式中只有一个块表达式时,才会设置变量 prune 为false,此时映射集checkSet 和候选集set 指向同一个数组,见第3958~3963行、第3987~3989行的说明。

第3999~4004行:如果上下文是元素,而不是文档对象,则遍历映射集checkSet,如果其中的元素满足以下条件之一,则将候选集set中对应的元素放入结果集results:

是true。

是元素,并且包含在上下文context中。

第4006~4012行:如果上下文是文档对象,则遍历映射集checkSet,如果其中的元素满足以下全部条件,则将候选集set中对应的元素放入结果集results:

不是null。

是元素。

第4014~4016行:如果候选集checkSet不是数组,则可能是NodeList,这种情况只会在选择器表达式仅仅是简单的标签或类样式(如$( "div" )、$( ".red" ) )时才会出现,此时不需要筛选候选集set,并且映射集checkSet和候选集set会指向同一个数组,可以直接将映射集checkSet插入结果集results中。见第3958~3963行、第3987~3989行的说明。

8.?如果存在并列选择器表达式,则递归调用Sizzle( selector, context, results, seed )查找匹配的元素集合,并合并、排序、去重

相关代码如下所示:

4018     if ( extra ) {

4019         Sizzle( extra, origContext, results, seed );

4020         Sizzle.uniqueSort( results );

4021     }

4022

第4020行:方法Sizzle.uniqueSort( results )负责对元素集合中的元素排序、去重,具体请参见3.10.1节。

9.?最后返回结果集results

相关代码如下所示:

4023     return results;

4024 };

函数Sizzle( selector, context, results, seed )的执行过程可以总结为图3-3。

相关文章
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
AI技术深度解析:从基础到应用的全面介绍
人工智能(AI)技术的迅猛发展,正在深刻改变着我们的生活和工作方式。从自然语言处理(NLP)到机器学习,从神经网络到大型语言模型(LLM),AI技术的每一次进步都带来了前所未有的机遇和挑战。本文将从背景、历史、业务场景、Python代码示例、流程图以及如何上手等多个方面,对AI技术中的关键组件进行深度解析,为读者呈现一个全面而深入的AI技术世界。
223 10
|
11天前
|
机器学习/深度学习 人工智能 算法
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
DeepSeek-R1 通过创新的训练策略实现了显著的成本降低,同时保持了卓越的模型性能。本文将详细分析其核心训练方法。
289 11
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
|
4天前
|
人工智能 自然语言处理 算法
DeepSeek模型的突破:性能超越R1满血版的关键技术解析
上海AI实验室周伯文团队的最新研究显示,7B版本的DeepSeek模型在性能上超越了R1满血版。该成果强调了计算最优Test-Time Scaling的重要性,并提出了一种创新的“弱到强”优化监督机制的研究思路,区别于传统的“从强到弱”策略。这一方法不仅提升了模型性能,还为未来AI研究提供了新方向。
168 5
|
30天前
|
缓存 算法 Oracle
深度干货 如何兼顾性能与可靠性?一文解析YashanDB主备高可用技术
数据库高可用(High Availability,HA)是指在系统遇到故障或异常情况时,能够自动快速地恢复并保持服务可用性的能力。如果数据库只有一个实例,该实例所在的服务器一旦发生故障,那就很难在短时间内恢复服务。长时间的服务中断会造成很大的损失,因此数据库高可用一般通过多实例副本冗余实现,如果一个实例发生故障,则可以将业务转移到另一个实例,快速恢复服务。
深度干货  如何兼顾性能与可靠性?一文解析YashanDB主备高可用技术
|
1月前
|
Serverless 对象存储 人工智能
智能文件解析:体验阿里云多模态信息提取解决方案
在当今数据驱动的时代,信息的获取和处理效率直接影响着企业决策的速度和质量。然而,面对日益多样化的文件格式(文本、图像、音频、视频),传统的处理方法显然已经无法满足需求。
93 4
智能文件解析:体验阿里云多模态信息提取解决方案
|
1月前
|
Kubernetes Linux 虚拟化
入门级容器技术解析:Docker和K8s的区别与关系
本文介绍了容器技术的发展历程及其重要组成部分Docker和Kubernetes。从传统物理机到虚拟机,再到容器化,每一步都旨在更高效地利用服务器资源并简化应用部署。容器技术通过隔离环境、减少依赖冲突和提高可移植性,解决了传统部署方式中的诸多问题。Docker作为容器化平台,专注于创建和管理容器;而Kubernetes则是一个强大的容器编排系统,用于自动化部署、扩展和管理容器化应用。两者相辅相成,共同推动了现代云原生应用的快速发展。
180 11
|
2月前
|
域名解析 负载均衡 安全
DNS技术标准趋势和安全研究
本文探讨了互联网域名基础设施的结构性安全风险,由清华大学段教授团队多年研究总结。文章指出,DNS系统的安全性不仅受代码实现影响,更源于其设计、实现、运营及治理中的固有缺陷。主要风险包括协议设计缺陷(如明文传输)、生态演进隐患(如单点故障增加)和薄弱的信任关系(如威胁情报被操纵)。团队通过多项研究揭示了这些深层次问题,并呼吁构建更加可信的DNS基础设施,以保障全球互联网的安全稳定运行。
|
2月前
|
缓存 网络协议 安全
融合DNS技术产品和生态
本文介绍了阿里云在互联网基础资源领域的最新进展和解决方案,重点围绕共筑韧性寻址、赋能新质生产展开。随着应用规模的增长,基础服务的韧性变得尤为重要。阿里云作为互联网资源的践行者,致力于推动互联网基础资源技术研究和自主创新,打造更韧性的寻址基础服务。文章还详细介绍了浙江省IPv6创新实验室的成立背景与工作进展,以及阿里云在IPv6规模化部署、DNS产品能力升级等方面的成果。此外,阿里云通过端云融合场景下的企业级DNS服务,帮助企业构建稳定安全的DNS系统,确保企业在数字世界中的稳定运行。最后,文章强调了全链路极致高可用的企业DNS解决方案,为全球互联网基础资源的创新提供了中国标准和数字化解决方案。
|
2月前
|
缓存 边缘计算 网络协议
深入解析CDN技术:加速互联网内容分发的幕后英雄
内容分发网络(CDN)是现代互联网架构的重要组成部分,通过全球分布的服务器节点,加速网站、应用和多媒体内容的传递。它不仅提升了访问速度和用户体验,还减轻了源站服务器的负担。CDN的核心技术包括缓存机制、动态加速、流媒体加速和安全防护,广泛应用于静态资源、动态内容、视频直播及大文件下载等场景,具有低延迟、高带宽、稳定性强等优势,有效降低成本并保障安全。
126 4
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
秒级响应 + 99.9%准确率:法律行业文本比对技术解析
本工具基于先进AI技术,采用自然语言处理和语义匹配算法,支持PDF、Word等格式,实现法律文本的智能化比对。具备高精度语义匹配、多格式兼容、高性能架构及智能化标注与可视化等特点,有效解决文本复杂性和法规更新难题,提升法律行业工作效率。

热门文章

最新文章

推荐镜像

更多