正则表达式的环视深度剖析

文章目录

  • 一、环视基础
  • 二、顺序环视匹配过程
    • (一)顺序肯定环视匹配过程
    • (二)顺序否定环视匹配过程
  • 三、逆序环视匹配过程
    • (一)逆序环视基础
    • (二)逆序肯定环视匹配过程
      • 1. 逆序表达式的长度固定,如何匹配
      • 2. 逆序表达式的长度不固定,如何匹配
        • (1)匹配开始位置不确定,匹配结束位置确定
        • (2)匹配开始位置确定,匹配结束位置不确定
    • (三)逆序否定环视匹配过程
      • 1. 逆序表达式的长度固定,如何匹配
        • (1)匹配起始位置不确定,匹配结束位置确定
        • (2)匹配起始位置确定,匹配结束位置不确定
      • 2. 逆序表达式的长度不固定,如何匹配

一、环视基础

环视只进行子表达式的匹配,不占有字符,匹配到的内容不保存到最终的匹配结果,是零宽度的。环视匹配的最终结果就是一个位置。

环视的作用相当于对所在位置加了一个附加条件,只有满足这个条件,环视子表达式才能匹配成功。

环视按照方向划分有顺序和逆序两种,按照是否匹配有肯定和否定两种,组合起来就有四种环视。顺序环视相当于在当前位置右侧附加一个条件,而逆序环视相当于在当前位置左侧附加一个条件。

表达式说明
(?<=Expression)逆序肯定环视,表示所在位置左侧能够匹配 Expression
(?<!Expression)逆序否定环视,表示所在位置左侧不能匹配 Expression
(?=Expression)顺序肯定环视,表示所在位置右侧能够匹配 Expression
(?!Expression)顺序否定环视,表示所在位置右侧不能匹配 Expression

环视是正则中的一个难点,对于环视的理解,可以从应用和原理两个角度理解,如果想理解得更清晰、深入一些,还是从原理的角度理解好一些,正则匹配基本原理参考《NFA引擎匹配原理》。

上面提到环视相当于对“所在位置”附加了一个条件,环视的难点在于找到这个“位置”,这一点解决了,环视也就没什么秘密可言了。

对于顺序肯定环视(?=Expression)来说,当子表达式Expression匹配成功时,(?=Expression)匹配成功,并报告(?=Expression)匹配当前位置成功。

对于顺序否定环视(?!Expression)来说,当子表达式Expression匹配成功时,(?!Expression)匹配失败;当子表达式Expression匹配失败时,(?!Expression)匹配成功,并报告(?!Expression)匹配当前位置成功。

二、顺序环视匹配过程

(一)顺序肯定环视匹配过程

顺序肯定环视的例子已在《NFA引擎匹配原理》中讲解过了,请移步参考。

(二)顺序否定环视匹配过程

源字符串:aa<p>one</p>bb<div>two</div>cc

正则表达式:<(?!/?p\b)[^>]+>

这个正则的意义就是匹配除 <p></p>之外的其余标签。/? 表示匹配正斜杠 0 次或 1 次;\b 表示匹配字符边界。

在这里插入图片描述

首先由表达式的字符 < 取得控制权,从源字符串位置 0 开始匹配,由于 < 匹配 a 失败,在位置 0 处整个表达式匹配失败,第一次迭代匹配失败,正则引擎向前传动,由位置 1 处开始尝试第二次迭代匹配。

重复以上过程,直到位置 2,表达式的字符 < 匹配源字符串的字符 < 成功,控制权交给 (?!/?p\b)(?!/?p\b) 子表达式取得控制权后,进行内部子表达式的匹配。首先由 /? 取得控制权,尝试匹配 p 失败,进行回溯,不匹配,控制权交给 p;由 p 来尝试匹配 p,匹配成功,控制权交给 \b;由 \b 来尝试匹配位置 4,匹配成功。此时子表达式匹配完成,/?p\b 匹配成功,那么环视表达式 (?!/?p\b) 就匹配失败。在位置 2 处整个表达式匹配失败,新一轮迭代匹配失败,正则引擎向前传动,由位置 3 处开始尝试下一轮迭代匹配。

在位置 8 处也会遇到一轮 /?p\b 匹配 /p 成功,而导致环视表达式 (?!/?p\b) 匹配失败,从而导致整个表达式匹配失败的过程。

重复以上过程,直到位置 14,< 匹配 < 成功,控制权交给 (?!/?p\b)/? 尝试匹配 d 失败,进行回溯,不匹配,控制权交给 p;由 p 来尝试匹配 d,匹配失败,已经没有备选状态可供回溯,匹配失败。此时子表达式匹配完成,/?p\b 匹配失败,那么环视表达式 (?!/?p\b) 就匹配成功。匹配的结果是位置15,然后控制权交给 [^>]+;由 [^>]+ 从位置 15 进行尝试匹配,可以成功匹配到 div,控制权交给 >;由 >来匹配 >,匹配成功。此时正则表达式匹配完成,报告匹配成功。

匹配结果为 <div>,开始位置为 14,结束位置为 19。其中 < 匹配 <(?!/?p\b) 匹配位置 15,[^>]+ 匹配字符串 div> 匹配 >

在这里插入图片描述

三、逆序环视匹配过程

(一)逆序环视基础

对于逆序肯定环视 (?<=Expression) 来说,当子表达式 Expression 匹配成功时,(?<=Expression) 匹配成功,并报告 (?<=Expression) 匹配当前位置成功。

对于逆序否定环视 (?<!Expression) 来说,当子表达式 Expression 匹配成功时,(?<!Expression) 匹配失败;当子表达式 Expression 匹配失败时,(?<!Expression)匹配成功,并报告(?<!Expression)匹配当前位置成功;

顺序环视相当于在当前位置右侧附加一个条件,所以它的匹配尝试是从当前位置开始的,然后向右尝试匹配,直到某一位置使得匹配成功或失败为止。而逆序环视的特殊处在于,它相当于在当前位置左侧附加一个条件,所以它不是在当前位置开始尝试匹配的,而是从当前位置左侧某一位置开始,匹配到当前位置为止,报告匹配成功或失败。

顺序环视尝试匹配的起点是确定的,就是当前位置,而匹配的终点是不确定的。逆序环视匹配的起点是不确定的,是当前位置左侧某一位置,而匹配的终点是确定的,就是当前位置。

所以顺序环视相对是简单的,而逆序环视相对是复杂的。这也就是为什么大多数语言和工具都提供了对顺序环视的支持,而只有少数语言提供了对逆序环视支持的原因。

JavaScript 中只支持顺序环视,不支持逆序环视。

Java 中虽然顺序环视和逆序环视都支持,但是逆序环视只支持长度确定的表达式,逆序环视中量词只支持“?”,不支持其它长度不定的量词。长度确定时,引擎可以向左查找固定长度的位置作为起点开始尝试匹配,而如果长度不确定时,就要从当前位置向左逐个位置开始尝试匹配,不成功则回溯,再向左侧位置进行尝试匹配,然后重复以上过程,直到匹配成功,或是尝试到位置0处以后,报告匹配失败,处理的复杂度是显而易见的。

目前只有.NET中支持不确定长度的逆序环视。

(二)逆序肯定环视匹配过程

1. 逆序表达式的长度固定,如何匹配

源字符串:<div>a test</div>

正则表达式:(?<=<div>)[^<]+(?=</div>)

这个正则的意义就是匹配 <div></div> 标签之间的内容,而不包括 <div></div>标签本身。

在这里插入图片描述
首先由逆序肯定环视表达式 (?<=<div>) 取得控制权,从位置 0 开始匹配,由于逆序肯定环视表达式中的子表达式 <div> 长度是 5,所以正则引擎会从当前位置向左侧查找 5 个字符来匹配,可是当前位置是 0,左侧没有任何内容,所以子表达式 <div> 必然匹配失败,从而逆序肯定环视表达式 (?<=<div>) 匹配失败,则整个正则表达式在字符串的位置 0 处匹配失败,即正则表达式的第 1 轮迭代匹配失败。

正则引擎向前传动,由位置 1 处开始尝试第 2 次迭代匹配,由于位置左侧的字符数量不足,所以也是匹配失败。直到传动到位置 5,正则引擎向左查找到 5 个字符,(?<=<div>) 取得控制权后,由位置 0 开始向右逐个字符匹配,结果子表达式 <div> 匹配字符串 <div> 成功,从而整个逆序肯定环视表达式 (?<=<div>) 匹配成功,匹配成功的位置是 5,控制权交给下一个子表达式 [^<]+[^<]+ 从位置 5 向右开始逐个字符匹配,匹配字符串 a test 成功,控制权交给顺序肯定环视表达式 (?=</div>);由 </div> 匹配 </div> 成功,从而顺序肯定环视表达式 (?=</div>) 匹配成功,位置 11 匹配成功。

此时正则表达式匹配完成,报告匹配成功。匹配到的字符串为 a test,匹配开始位置为 5,匹配结束位置为 11。其中 (?<=<div>) 匹配位置 5[^<]+ 匹配字符串 a test(?=</div>) 匹配位置 11

疑问:
逆序环视表达式的匹配是如何确定匹配开始位置的?如果是按照表达式的长度向左查找对应数量的字符数,从而确定匹配起点,那么当前位置左侧的字符数量不足时,匹配起点位置就无法确定,也就不会逐个字符去匹配了,因为长度都不同,匹配结果肯定是失败的。猜测,大概率是按逆序环视子表达式的长度(或者最小长度)来确定起点,如果字符数不足,就没有必要逐个字符去匹配,因为这是多余的,匹配结果肯定是失败的。

2. 逆序表达式的长度不固定,如何匹配

源字符串:<div id=“test1”>a test</div>

正则表达式:(?<=<div[^>]*>)[^<]+(?=</div>)
在这里插入图片描述

(1)匹配开始位置不确定,匹配结束位置确定

注:我不认可这样的匹配逻辑。

首先由“(?<=<div[^>]*>)”取得控制权,由位置 0 开始匹配,由于“<div[^>]*>”的长度不固定,可能会由逆序环视表达式的第 1 个字符从当前位置向左逐字符查找(这个可能性不大,因为太傻了!);有可能是先计算逆序表达式最小长度,然后在当前位置向前查找初始的匹配起点位置。在这里“<div[^>]*>”至少需要 5 个字符,所以由当前位置向左查找 5 个字符,然后再从左到右的方向,从这 5 个字符的第 1 个字符开始尝试匹配,但是由于此时位于位置 0处,前面没有任何字符,所以尝试匹配失败。

正则引擎传动装置向右传动,由位置 1 处开始尝试匹配,同样因为左侧的字符数不足,所以直接匹配失败,直到位置 5 处,向左查找 5 个字符,满足条件,此时把控制权交给“(?<=<div[^>]*>)”中的子表达式“<div[^>]*>”。“<div[^>]*>”取得控制权后,由位置 0 处开始向右尝试匹配,由于正则都是逐字符进行匹配的,所以这时会把控制权交给“<div[^>]*>”中的“<”,由“<”尝试匹配字符串中的“<”,匹配成功,接下来由“d”尝试匹配字符串中的“d”,匹配成功,同样的过程,由“<div[^>]*”匹配位置 0 到位置 5 之间的“<div ”成功,其中“[^>]*”在匹配“<div ”中的空格时会记录可供回溯的状态的,此时控制权交给“>”,由于已没有任何字符可供匹配,所以“>”匹配失败,此时进行回溯,由“[^>]*”让出已匹配的空格给“>”进行匹配,同样匹配失败,此时已没有可供回溯的状态,所以这一轮迭代匹配失败。

正则引擎传动装置向右传动,由位置 6 处开始尝试匹配,同样匹配失败,直到位置 16 处,此时的当前位置指的就是位置 16,向左查找到 5 个字符,把控制权交给“(?<=<div[^>]*>)”中的子表达式“<div[^>]*>”。“<div[^>]*>”取得控制权后,由位置 11 处开始向右尝试匹配, “<div[^>]*>”中的“<”尝试匹配字符串中的“s”,匹配失败;继续向左尝试,在位置 10 处由“<”尝试匹配字符串中的“e”,也匹配失败。同样的过程,直到尝试到位置 0 处,最后“<div[^>]*>”以位置 0 作为匹配起点,向右匹配,结果成功匹配到“<div id=“test1”>”,此时“(?<=<div[^>]*>)”匹配成功,控制权交给“[^>]+”,继续进行下面的匹配…

注:我认为这样的匹配规则是错误的,因为“<div[^>]*>”中的“<”匹配失败后往左尝试匹配,这样的做法很不合理,为什么?假设“<”继续向左尝试匹配,最后匹配成功了,控制权交个下个表达式,而该表达式匹配失败了,“<”会继续向左尝试匹配,可能又匹配成功了,但是下个表达式又匹配失败,这样的匹配逻辑肯定不对!!!

(2)匹配开始位置确定,匹配结束位置不确定

注:这个更符合逆序的概念,也更加合理,我认可这种匹配逻辑!

源字符串:<div>a test</div>

正则表达式:(?<=<div>)[^<]+(?=</div>)

(?<=<div>)”获得控制权,从源字符串位置 0 开始向左匹配,首先“>” 去匹配,但是位置 0 左侧没有字符,所以匹配失败,第 1 次迭代匹配失败;接着正则引擎指针向右移动,“>” 去匹配字符串的字符“<”,匹配失败,第 2 次迭代匹配失败。

重复上述过程,直到位置 5,子表达式“<div>”中的“>” 去匹配位置 5 左边的第 1 个字符“>”,匹配成功;子表达式“<div>”中的“v”去匹配位置 5 左边第 2 个字符“v”,匹配成功…,最后子表达式“<div>”成功匹配位置 5 左边的字符串“<div>”,那么说明逆序肯定环视表达式“(?<=<div>)”匹配成功,即成功匹配位置 5;接着控制权给表达式“[^<]+”,该表达式从位置 5 开始向右逐个字符匹配,最后成功匹配到字符串“a test”,接着把控制权交个子表达式“(?=</div>)”,由它去验证字符串“a test”的结尾位置 11 是否符合正则式的要求,结果“(?=</div>)”成功匹配到了字符串“a test”后面的字符串“</div>”,说明字符串“a test”的结尾位置 11 符合要求,后续没有子表达式了,说明正则表达式迭代匹配成功 1 次,成功匹配到字符串“a test”。接着从位置 11 开始下次迭代匹配…

后面重复上述的过程,直到正则引擎的指针移到字符串的结尾处,则停止迭代匹配。

(三)逆序否定环视匹配过程

源字符串:adf<B>BerBilBlon<B>Ssdfefe</B>dfee
正则表达式:(?<!<B>)B

1. 逆序表达式的长度固定,如何匹配

(1)匹配起始位置不确定,匹配结束位置确定

当前位置是匹配终点,匹配起点在当前位置的左侧,最终的匹配起点是不确定的,初始的匹配起点可以根据逆序表达式的长度来查找。

注:我认为这样的匹配逻辑是错误的,不认可

首先由“(?<!<B>)”的子表达式“<B>”取得控制权,由位置 0 开始尝匹配,由于“<B>”的长度固定为 3,所以会从当前位置向左查找 3个字符,但是由于此时位于位置 0 处,前面没有任何字符,所以直接匹配失败,“<B>”匹配失败,那么整个逆序否定环视表达式“(?<!<B>)”则匹配成功,所以位置 0 满足逆序否定环视表达式“(?<!<B>)”,那么控制权就传给了“B”,由“B”从位置 0 开始向右匹配字符,于是“B”就去匹配字符串中的“a”,结果匹配失败,那么第 1 次迭代匹配失败。

正则引擎传动装置向右传动,你可以理解为有个指针的东西向右移动,此时指针来到位置 1 处,由位置 1 处向左查找 3 个字符,但是前面只有 1 个字符 a,所以同样和“<B>”匹配失败,则整个逆序否定环视表达式“(?<!<B>)”匹配成功,控制权传给“B”,由“B”从位置 1 开始向右匹配字符,于是“B”就去匹配字符串中的“d”,结果匹配失败,那么第 2 次迭代匹配失败。

直到位置 3 处,向左查找到 3 个字符串“abc”,字符数满足条件,此时“(?<!<B>)”中的子表达式“<B>”获得控制权。“<B>”取得控制权后,由位置 0 处开始向右逐个字符匹配字符串“abc”,既然是逐字符进行匹配的,所以这时会把控制权交给“<B>”中的“<”,由“<”尝试匹配字符串中的“a”,匹配失败,那么“<B>”就和字符串“abc”匹配失败,则整个逆序否定环视表达式“(?<!<B>)”匹配成功,控制权传给“B”,由“B”从位置 3 开始向右匹配字符,于是“B”就去匹配字符串中的“<”,结果匹配失败,那么第 4 次迭代匹配失败。

正则引擎的传动指针继续向右移动,此时来到了位置 4,那么正则引擎向左查找 3 个字符来匹配,查找到的字符串就是“df<”,接着“<B>”获得控制权,从位置 1 开始向右逐个字符匹配,那么首先由“<B>”中的“<”去匹配字符“d”,匹配失败,那么整个逆序否定环视表达式“(?<!<B>)”匹配成功,控制权传给“B”,由“B”从位置 4 开始向右匹配字符,于是“B”就去匹配位置 4 后面的“B”,结果匹配成功。

重复上述的过程直到正则引擎的指针移到字符串结尾才结束迭代匹配。

最后匹配到的“B”,如下所示(高亮部分):
在这里插入图片描述

(2)匹配起始位置确定,匹配结束位置不确定

当前位置是匹配起点,逆序环视是从当前位置向左开始匹配的,匹配终点在当前位置的左侧。不少人认为应该是这样的匹配规则,因为更符合逆序的概念。我也支持这个匹配逻辑。

注:需要明确的一点,无论是什么样的正则表达式,都是要从字符串的位置 0 处开始尝试匹配的,这点没有变。

逆序否定环视表达式“(?<!<B>)B”中的“<B>”先获得控制权,因为匹配从右到左,所以子表达式“<B>”中的“>”会先获得控制权,去匹配字符串当前位置左边的第 1 个字符,不过当前位置是 0,所以左侧没有字符,固然匹配失败,既然“<B>”匹配失败,那么整个逆序否定环视表达式“(?<!<B>)B”就匹配成功,也就是说位置 0 是匹配成功的,位置 0 是满足逆序否定环视表达式的,于是控制权交给“B”,由“B”从字符串位置 0 开始向右匹配字符,显然“B”匹配“a”是失败的,因此整个正则表达式的第 1 次迭代匹配失败。

重复上述的过程,直到位置 4,“<B>”从位置 4 开始向左逐个字符匹配,首先由“>”匹配位置 4 左边的第 1 个字符“<”,结果匹配失败,于是整个逆序否定环视表达式“(?<!<B>)B”匹配成功,也就是说位置 4 匹配成功,控制权交个了“B”,由“B”从位置 4 开始向右匹配字符,显示“B”与字符“B”匹配成功。

重复上述过程,直到正则引擎的指针移到位置 6 时,“<B>”逐个字符匹配位置 6 左侧的字符,首先“<B>”中的“>”先去匹配位置 6 左边的第 1 个字符“>”,匹配成功;接着“<B>”中的“B”去匹配位置 6 左边的第 2 个字符“B”,也匹配成功;接着“<B>”中的“<”去匹配位置 6 左边的第 3 个字符“<”,也匹配成功。那么最后“<B>”成功匹配到位置 6 左边的字符串“<B>”,因为是否定环视,所以整个逆序否定环视表达式匹配失败(即位置 6 不符合要求),所以整个正则表达式的迭代匹配失败,正则引擎的指针继续向后移。

重复上述过程,直到正则引擎指针移到字符串结尾处,正则迭代匹配结束。

2. 逆序表达式的长度不固定,如何匹配

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/333778.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习pytorch--softmax回归(一)

softmax回归 前几节介绍的线性回归模型适用于输出为连续值的情景。在另一类情景中&#xff0c;模型输出可以是一个像图像类别这样的离散值。对于这样的离散值预测问题&#xff0c;我们可以使用诸如softmax回归在内的分类模型。和线性回归不同&#xff0c;softmax回归的输出单元…

python比较excel表格内容并提取_利用python提取多张excel表数据并汇总到同一张新表中...

接上篇文章《如何用python实现excel中的vlookup功能&#xff1f;》&#xff0c;上篇说到&#xff0c;最近我在做一个小项目&#xff0c;也是用python操作excel解决财务审计工作上的一些问题&#xff0c;以便提高工作效率及其准确性。最终目的&#xff0c;刀哥是想做应收账款账龄…

阿帕奇跨域_阿帕奇齿轮泵

阿帕奇跨域Apache Gearpump是一个实时大数据流引擎。 它于2014年中期在GitHub上作为一个开源项目在英特尔构想&#xff0c;并于2016年3月8日进入Apache孵化。Gearpump的名称是对工程术语“齿轮泵”的指称&#xff0c;它是一个超级简单的泵&#xff0c;由以下组成只有两个齿轮&a…

正则表达式之 NFA 引擎匹配原理详解

文章目录一、为什么要了解引擎匹配原理二、正则表达式引擎三、预备知识&#xff08;一&#xff09;字符串组成&#xff08;二&#xff09;占有字符和零宽度&#xff08;三&#xff09;控制权和传动四、正则表达式简单匹本过程&#xff08;一&#xff09;基础匹配过程&#xff0…

阿帕奇跨域_阿帕奇光束

阿帕奇跨域Apache Beam是一个开放源代码统一模型&#xff0c;用于定义批处理和流数据并行处理管道。 使用一种开源的Beam SDK&#xff0c;您可以构建一个定义管道的程序。 然后&#xff0c;该管道由Beam支持的分布式处理后端之一执行&#xff0c;这些后端包括Apache Apex &…

unity 启动相机_Unity3D研究院之打开照相机与本地相册进行裁剪显示(三十三)...

最近做项目需要用到这个功能&#xff0c;就是在Unity中调用Android本地相册或直接打开摄像机拍照并且裁剪一部分用于用户头像&#xff0c;今天研究了一下&#xff0c;那么研究出成果了MOMO一定要分享给大家。Unity与Android的交互还有谁不会&#xff1f;&#xff1f; 如果有不会…

深度学习pytorch--MNIST数据集

图像分类数据集&#xff08;Fashion-MNIST&#xff09; 在介绍softmax回归的实现前我们先引入一个多类图像分类数据集。它将在后面的章节中被多次使用&#xff0c;以方便我们观察比较算法之间在模型精度和计算效率上的区别。图像分类数据集中最常用的是手写数字识别数据集MNIS…

html 元素的属性

全局属性 全局属性是可与所有 HTML 元素一起使用的属性。 事件属性 用来定义某个事件的操作的属性叫事件属性&#xff0c;例如&#xff0c;οnclick“script”&#xff0c;元素上发生鼠标点击时触发 click 事件&#xff0c;click 事件被触发就会执行对应的脚本代码。事件属性…

nosql和rdnms_用于SaaS和NoSQL的Jdbi

nosql和rdnms一个自然的接口&#xff0c;用于与CRM&#xff0c;ERP&#xff0c;会计&#xff0c;营销自动化&#xff0c;NoSQL&#xff0c;平面文件等基于Java的数据集成 Jdbi是用于JavaSQL便利库&#xff0c;它为JDBC提供更自然的Java数据库接口&#xff0c;该接口易于绑定到…

matlab 功率谱密度 汉宁窗_如何理解随机振动的功率谱密度?

一、随机信号和正太分布有什么关系&#xff1f; 二、时域、频域之间功率守恒&#xff1f; 三、自相关又是个什么玩意&#xff1f;作为一个工程师&#xff0c;很多人对随机振动看着熟悉&#xff0c;却又实际陌生。熟悉是因为几乎每个产品在出厂时都要求要做随机振动试验&#xf…

深度学习pytorch--softmax回归(二)

softmax回归的从零开始实现实验前思考获取和读取数据获取数据集查看数据集查看下载后的.pt文件查看mnist_train和mnist_test读取数据集查看数据迭代器内容初始化模型参数定义softmax函数定义模型定义损失函数计算分类准确率模型评价--准确率开始训练可视化总结完整代码实验前思…

HTML块级元素/块标签/块元素

文章目录块元素的特点块元素清单block level element. 块级元素想在同一行显示需浮动或者 display:inline。 块元素的特点 每个块级元素都是独自占一行&#xff0c;其后的元素也只能另起一行&#xff0c;并不能两个元素共用一行&#xff1b; 元素的高度、宽度、行高、顶边距、…

物联卡查询流量_电信物联卡官网是多少?如何快速查询流量信息?

高速率设备的使用场景需要用到5G&#xff0c;中速率LET-Cat1应用范围更广&#xff0c;而低速率则要靠窄带物联网NB-IOT去维护了。这三种网络制式全都与物联网息息相关&#xff0c;这就能知道为什么国家层面对物联网基础设施建设这么重视了。电信物联卡在智能化硬件中有优秀表现…

java8日期转时间戳_Java 8日期和时间

java8日期转时间戳如今&#xff0c;一些应用程序仍在使用java.util.Date和java.util.Calendar API&#xff0c;包括使我们的生活更轻松地使用这些类型的库&#xff0c;例如JodaTime。 但是&#xff0c;Java 8引入了新的API来处理日期和时间&#xff0c;这使我们可以对日期和时间…

HTML行内元素/行级元素/内联元素/行标签/内联标签/行内标签/行元素

文章目录行内元素的特点行内元素清单可变元素列表inline element. 也叫行级元素、内联元素。行内元素默认设置宽度是不起作用&#xff0c;需设置 display:inline-block 或者 block 才行。 行内元素的特点 可以和其他元素处于一行&#xff0c;不用必须另起一行&#xff1b; 元…

深度学习pytorch--softmax回归(三)

softmax回归的简洁实现获取和读取数据定义和初始化模型softmax和交叉熵损失函数定义优化算法模型评价训练模型小结完整代码前两篇链接: 深度学习pytorch–softmax回归(一) 深度学习pytorch–softmax回归(二) 本文使用框架来实现模型。 获取和读取数据 我们仍然使用Fashion-M…

正则表达式的分类

文章目录一、正则表达式引擎二、正则表达式分类三、正则表达式比较四、Linux/OS X 下常用命令与正则表达式的关系一、正则表达式引擎 正则引擎大体上可分为不同的两类&#xff1a;DFA 和 NFA&#xff0c;而 NFA 又基本上可以分为传统型 NFA 和 POSIX NFA。 DFA(Deterministic …

spock测试_使用Spock测试您的代码

spock测试Spock是针对Java和Groovy应用程序的测试和规范框架。 Spock是&#xff1a; 极富表现力 简化测试的“给定/何时/然后” 语法 与大多数IDE和CI服务器兼容。 听起来不错&#xff1f; 通过快速访问Spock Web控制台&#xff0c;您可以非常快速地开始使用Spock。 当您有…

深度学习pytorch--多层感知机(一)

多层感知机隐藏层激活函数ReLU函数sigmoid函数tanh函数多层感知机小结我们已经介绍了包括线性回归和softmax回归在内的单层神经网络。然而深度学习主要关注多层模型。在本节中&#xff0c;我们将以多层感知机&#xff08;multilayer perceptron&#xff0c;MLP&#xff09;为例…

太阳能板如何串联_光伏板清洁专用的清洁毛刷

光伏发电是利用半导体界面的光生伏特效应将光能直接转变为电能的一种技术。主要由太阳电池板&#xff08;组件&#xff09;、控制器和逆变器三大部分组成。主要部件由电子元器件构成。太阳能电池经过串联后进行封装保护可形成大面积的太阳电池组件&#xff0c;再配合上功率控制…