[记录] JavaScript 中的正则表达式
正则:
正则表达式,又称规则表达式。是匹配模式,要么匹配字符,要么匹配位置。
正则表达式的两种创建方式:
// 直接字面量 var reg = /^\d|\d$/gmi;// 构造函数 new RegExp(); var reg = new RegExp('^\d|\d$', 'gmi'); 注意:RegExp 构造函数的两个参数都是字符串;
正则对象的实例属性:
修饰符相关, 返回一个布尔值,表示是否设置了对于的修饰符。
RegExp.prototype.ignoreCase // 表示是否设置了忽略大小 i 修饰符 RegExp.prototype.global // 表示是否设置了全局匹配 g 修饰符 RegExp.prototype.multiline // 表示是否设置了多行匹配 m 修饰符var reg = /abc/igm; reg.ignoreCase // true reg.global // true reg.multiline // true
其他属性
RegExp.prototype.lastIndex // 返回一个整数, 表示下一次开始搜索的位置。可读可写,搜索时才有用 RegExp.prototype.source //返回正则标的是的字符串形式var reg = /abc/igm; reg.lastIndex // 0 reg.source // "abc"
正则的实例方法:
RegExp.prototype.test();
用来检查字符串是否匹配某个正则表达式,匹配返回true,否则返回false;
/hello/.test("hello word!"); // true
如果正则表示带有 g 修饰符, 则每次 test 方法都是从上一次结束的位置开始向后匹配。
var reg = /a/g; var str = "_a_a"; console.log( reg.lastIndex ); // 0 reg.test( str ); // trueconsole.log( reg.lastIndex ); // 2 reg.test( str ); // trueconsole.log( reg.lastIndex ); // 4 reg.test( str ); // false
RegExp.prototype.exec();
a. 匹配失败, 返回 null
b. 匹配成功, 返回一个数组, 成员是匹配成功的子字符串
c. 全局匹配时, lastIndex 为累加, 下一次搜索的位置是上一次匹配成功结束的位置
var str = "a-b-c"; /a/.exec(str); // ["a"] /d/.exec(str); // null
利用g修饰符允许多次匹配的特点,可以用一个循环完成全局匹配
var reg = /a/g; var str = "abc-abc-abc"; while( true ){var match = reg.exec(str);if(!match){break;}console.log("#" + match.index + ":" + match[0]); } // #0:a // #4:a // #8:a
字符串的实例方法:
String.prototype.match()
a. 匹配成功, 返回一个数组, 成员是所有的匹配的子字符串 b. 匹配失败, 返回null c. 带有g修饰符时, 会一次性返回所有匹配成结果 d. 匹配总是从字符串的第一个字符位置开始 var string = "2017-06-26"; console.log( string.match(/\d+/g) ); // ["2017", "06", "26"] console.log( string.match(/\d{5}/g) ); // null
String.prototype.search()
a. 返回第一个满足条件的匹配结果在整个字符串的位置 b. 匹配失败, 返回 -1 var str = "abcdefg"; console.log( str.search(/\d/g) ); // -1 console.log( str.search(/d/g) ); // 3 注: 忽略全局匹配g修饰符, 只要匹配上就不再匹配
String.prototype.replace()
按照给定的正则表达式进行替换, 返回替换后的字符串
接受两个参数:
A. 第一个参数是正则表达式, 表示搜索模式
B. 第二个参数是替换的内容, 可以是字符串, 也可以是函数
var str = "aaa"; str.replace("a", "b"); // "baa" str.replace(/a/, "b"); // "baa" str.replace(/a/g, "b"); // "bbb" 全局匹配替换
当第二个参数是字符串时, 以下的字符有特殊的含义:
$& : 匹配到的子串文本
$` : 匹配到的子串的左边文本
$' : 匹配到的子串的右边文本
$n : 匹配成功的第n组内容, n 是从1开始的自然数
$$ : 美元符号
例如: 把"2,3,5", 变成"5=2+3"
var str = "2,3,5"; console.log( str.replace(/(\d+),(\d+),(\d+)/, "$3=$1+$2") ); // "5=2+3"
例如: 把"2,3,5", 变成"222,333,555"
var str = "2,3,5"; console.log( str.replace(/(\d+)/g, "$&$&$&") ); // "222,333,555"
例如: 把"2+3=5", 变成"2+3=2+3=5=5"
var str = "2+3=5"; console.log( str.replace(/=/, "$&$`$&$'$&") ); // "2+3=2+3=5=5"
第二个参数是函数时
var str = "1234 2345 3456"; var reg = /(\d)\d{2}(\d)/g str.replace(reg, function(match, $1, $2, index, input){// match : 匹配到的内容// $1\$2 : 捕获到分组中的内容// index : 匹配到的内容在整个字符串中的位置// input : 原字符串console.log([match, $1, $2, index, input]); }); // ["1234", "1", "4", 0, "1234 2345 3456"] // ["2345", "2", "5", 5, "1234 2345 3456"] // ["3456", "3", "6", 10, "1234 2345 3456"]
String.prototype.split()
按照给定规则进行字符串分割, 返回一个数组
例如: 目标字符串是"html,css,javascript", 按逗号来分隔
var str = "html,css,javascript"; console.log( str.split(/,/) ); // ["html", "css", "javascript"]
分隔日期格式
var reg = /\D/; console.log( "2018/09/05".split(reg) ); // ["2018", "09", "05"] console.log( "2018-09-05".split(reg) ); // ["2018", "09", "05"] console.log( "2018.09.05".split(reg) ); // ["2018", "09", "05"]
正则表达式匹配规则:
字符组:
方括号[] 用来查找某个范围内的字符, 是是其中一个字符
[abc] => 表示或者的意思,匹配一个字符,可以是"a"、"b"、"c"之一
[^abc] => ^表示求反,是一个除"a"、"b"、"c"之外的任意一个字符
[0-9] => -是连字符,0到9的数字
[A-z] => 大写A 到 小写z 的字符
纵向模糊匹配:
指的是,一个正则匹配的字符串,具体到某一位字符串时,它可以不是某个确定的字符。
实现的方式是使用字符组。如: [abc], 表示可以是"a"、"b"、"c"中的任何一个。
var reg = /a[123]b/g; var str = "a0b a1b a2b a3b a4b"; console.log( str.match(reg) ); // ["a1b", "a2b", "a3b"]
量词(匹配重复):
{m} => 表示出现 m 次
{m, } => 表示至少出现 m 次
{m, n} => 表示出现 m 次 到 n 次
? => 等价于{0,1}, 0次 或 1次
+ => 等价于{1, }, 1次 或 多次
* => 等价于{0, }, 0次 或 多次
横向模糊匹配:
指的是,一个正则可匹配的字符串的长度是不固定的,可以是多种情况的。
实现的方式是使用量词。如: b{2, 5} 连续出现最少2次,最多5次
例: 正则表达式/ab{2, 5}c/g; 表示匹配这样一个字符串: 第一个字符是"a", 接下来是2到5个"b"字符, 最后一个是"c"字符。
var reg = /ab{2, 5}c/g; var str = "abc abbc abbbc abbbbc abbbbbc abbbbbbc"; console.log( str.match(reg) ); // ["abbc", "abbbc", "abbbbc", "abbbbbc"]
多选分支: 也是惰性匹配,即当前匹配上了,就不再往后尝试
(p1|p2|p3),其中p1、p2、p3是子模式,用 | 分隔,表示其中任何一个.
var reg = /good|nice/g; var str = 'good idea, nice try.'; console.log( str.match(reg) ); // ["good", "nice"]
多选分支的惰性匹配
var reg = /goodbye|good/g; var str = "goodbye"; console.log( str.match(reg) ); // ["goodbye"]
贪婪匹配和惰性匹配:
*?、+?、??、{}?
贪婪匹配: 是尽可能的多匹配;
var reg = /\d{2, 5}/g; var str = "123 1234 12345 123456"; console.log( str.match(reg) ); // ["123", "1234", "12345", "12345"] 注: /\d{2,5}/表示,数字连续出现2到5次,会匹配2位、3位、4位、5位连续数字
惰性匹配:尽可能的少匹配;
var regex = /\d{2,5}?/g; var string = "123 1234 12345 123456"; console.log( string.match(regex) ); // ["12", "12", "34", "12", "34", "12", "34", "56"] 注: /\d{2,5}?/表示,数字连续出现2到5次都行,当2个就够的时候,就不再往下尝试了。
预定义模式:
// 数字 \d 等价于 [0-9], 表示是一位数字 // 非数字 \D 等价于 [^0-9], 表示除数字外的任意字符// 数字、字母、下划线 \w 等价于 [0-9a-zA-Z_], 表示数字、字母、下划线, 称单词字符 // 非单词字符 \W 等价于 [^0-9a-zA-Z_], 表示非单词字符\s 等价于 [ \t\v\n\r\f], 表示空白符 \S 等价于 [^ \t\v\n\r\f], 表示非空白符. 等价于 [^\n\r\u2028\u2029] 通配符 除换行符、回车符、行分隔符、段分隔符以外 任意字符匹配任意字符: [\d\D]、[\w\W]、[\s\S]、[^] 中任何一个
正则表达式位置匹配:
正则的匹配模式, 要么匹配字符, 要么匹配位置。
什么是位置, 如图: (字符与字符之间的位置)
锚字符:
^ => 匹配开头,在多行匹配中匹配行开头
$ => 匹配结尾,在多行匹配中匹配行结尾
匹配开头 和 匹配结尾 var result = 'hello'.replace(/^|$/g, '#'); console.log( result ); // "#hello#"多行匹配模式时,二者是行的概念 var result = "I\nlove\njavascript".replace(/^|$/gm, '#'); console.log( result ); /* #I# #love# #javascript# */
\b => 单词边界, 是\w和\W之间的位置, 包括\w和^|$之间的位置
\B => 非单词边界, 是\w和\w、\W和\W、^|$和\W之间的位置
单词边界 和 非边界 var result = "[JS] Lesson_01.mp4".replace(/\b/g,'#'); console.log( result ); // "[#JS#] #Lesson_01#.#mp4#"
分解:
\w是字符组[0-9a-zA-Z_] 的简写形式,是数字字母或下划线的任何一个字符。
\W是排除字符组[^0-9a-zA-Z_]的简写形式,是除\w以外的任何一个字符
第一个"#", 两边是"["与"J", 是\W和\w之间的位置
第二个"#", 两边是"S"与"]", 也就是\w和\W之间的位置
第三个"#", 两边是空格与"L", 是\W和\w之间的位置
第四个"#", 两边是"1"与".", 是\w和\W之间的位置
第五个"#", 两边是"."与"m", 是\W和\w之间的位置
第六个"#", 对应的位置是结尾,字符"4"是\w,即\w和$之间的位置
非单词边界的位置:
\B 在字符串中所有位置中,扣掉\b,剩下的都是\B的。
具体说就是\w与\w、\W与\W、^与\W、\W与$之间的位置
var result = "[JS] Lesson_01.mp4".replace(/\B/g, '#'); console.log(result); // "#[J#S]# L#e#s#s#o#n#_#0#1.m#p#4"
x(?=y) 称之为先行断言, x只有在y前面才匹配, y不计入结果
var result = "hello word!".replace(/(?=o)/g,'#'); // 左看看 console.log( result ); // 表示是在o字符前面的位置替换"#" // "hell#o w#ord!"
x(?!y) 称之为先行否定断言, x只有不在y前面才匹配。
var result = "hello word!".replace(/(?!o)/g, '#'); console.log( result ); // 表示是在不是o字符前面的位置替换"#" // "#h#e#l#lo# #wo#r#d#!#"'3.14'.match(/\d+(?!\.)/g); // 右看看 // ["14"] 匹配不在小数点前面的数字/ 匹配小数点后面的数字
正则表达式括号的作用:
分组:
/a+/ 匹配连续出现的"a"
/(ab)+/ 匹配连续出现的"ab"
括号提供的是分组的功能,表示的是一个整体。
var reg = /(ab)+/g; var str = "ababa abbb ababab"; console.log( str.match(reg) ); // ["abab", "ab", "ababab"]
分支结构:
在多选分支结构(p1|p2)中,此处括号的作用也是一组,表示子表达式的所有可能。
var reg = /^I love (A | B)$/; console.log( reg.test("I love A") ); // true console.log( reg.test("I love B") ); // true console.log( reg.text("I love c") ); // false
引用分组:
提取数据
var reg = /(\d{4})-(\d{2})-(\d{2})/; console.log( "2018-09-01".match(reg) ); // ["2018-09-01", "2018", "09", "01", index: 0, input: "2018-09-01"] match 返回的一个数组,第一个是整体匹配结果,然后是各个分组匹配的内容。
也可以使用正则对象exec方法
var reg = /(\d{4})-(\d{2})-(\d{2})/; console.log( reg.exec("2018-09-01") ); // ["2018-09-01", "2018", "09", "01", index: 0, input: "2018-09-01"]
分组可以使用构造函数的全局属性 $1 至 $9 来获取
console.log( RegExp.$1 ); // "2018" console.log( RegExp.$2 ); // "09" console.log( RegExp.$3 ); // "01"
替换:
把yyyy-mm-dd格式,替换成 mm/dd/yyyy怎么做?
var reg = /(\d{4})-(\d{2})-(\d{2})/; "2018-09-01".replace(reg, "$2$3$1"); // "09/01/2018" 其中replace中的, 第二个参数里的 $1、$2、$3指代相应的分组。 等价于: var reg = /(\d{4})-(\d{2})-(\d{2})/; "2018-09-01".replace(reg, function(){return RegExp.$2 + "/" + RegExp.$3 + "/" + RegExp.$1; }); // "09/01/2018" 也等价于: var reg = /(\d{4})-(\d{2})-(\d{2})/; "2018-09-01".replace(reg, function(match, year, month, day){return month + "/" + day + "/" + year; }); // "09/01/2018"
反向引用: 在正则本身里引用分组,只能引用之前出现的分组,即反向引用。
匹配如下三种日期格式: 2018-09-01、2018/09/01、2018.09.01 var reg = /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/; console.log( reg.test("2018-09-01") ); // true console.log( reg.test("2018/09/01") ); // true console.log( reg.test("2018.09.01") ); // true console.log( reg.test("2018/09-01") ); // true
反向引用\1, 表示的引用之前那个分组(-|\/|\.) 指代的是第一个分组
var reg = /\d{4}(-|\/|\.)\d{2}\1\d{2}/; console.log( reg.test("2018-09-01") ); // true console.log( reg.test("2018/09/01") ); // true console.log( reg.test("2018.09.01") ); // true console.log( reg.test("2018/09-01") ); // true
括号嵌套: 以左括号(开括号) 为准。
var reg = /^((\d)(\d(\d)))\1\2\3\4$/; console.log( reg.test('1231231233') ); // true console.log( RegExp.$1 ); // 123 console.log( RegExp.$2 ); // 1 console.log( RegExp.$3 ); // 23 console.log( RegExp.$4 ); // 3
非捕获分组: 不能被引用
var reg = /(?:ab)+/g; console.log( "ababa abbb ababab".match(reg) ); // ["abab", "ab", "ababab"]
正则表达式操作符的优先级
1. 转义符 \
2. 括号和方括号 (...)、(?:...)、(?=...)、(?!...)、[...]
3. 量词限定符 {...}、?、*、+
4. 位置和序列 ^、$、\元字符、一般字符
5. 管道符 (| 或)
操作符的优先级从上往下,由高到低
分析:
/ab?(c|de*)+|fg/ - 由于括号的存在,所有,(c|de*) 是一个整体结构 - 在(c|de*)中,注意其中的量词 *, 因此e*是一个整体结构 - 因为分支结构"|"优先级最低,因此c是一个整体,de*是另一个整体 - 同理,整个正则分成了a、b?、(...)+、f、g, 由于分支的原因,又可以分成 ab?(c|de*)+ 和 fg这两部分
元字符转义问题:
所谓元字符,就是正则中有特殊含义的字符;
^ $ . * + ? | \ / ( ) [ ] { } = ! : - , var str = "^$.*+?|\\/[]{}=!:-,"; // 字符串中的\字符需要转义的 var reg = /\^\$\.\*\+\?\|\\\/\[\]\{\}\=\!\:\-\,/; console.log( reg.test(str) ); // true
字符组中的元字符
跟字符组相关的元字符有[]、^、-, 因此在会引起歧义的地方进行转义。
例如开头的^必须转义,不然会把整个字符组,看成反义字符组。 var str = "^$.*+?|\\/[]{}=!:-,"; var reg = /[\^$.*+?|\\/\[\]{}=!:\-,]/g; console.log( str.match(reg) ); // ["^", "$", ".", "*", "+", "?", "|", "\", "/", "[", "]", "{", "}", "=", "!", ":", "-", ","]
匹配"[abc]"和""
由于[abc]是一个字符组,要匹配字符串"[abc]"时,我们需要把正则中的元字符先进行转义如:/\[abc\]/ 或 /\[abc]/ 第一个方括号转义之后,后面的方括号构不成字符组,就不会引发歧义了。
var str = "[abc]"; var reg = /\[abc]/g; cosnole.log( str.match(reg)[0] ); // "[abc]"
= ! : - , 等符号,只要不在特殊结构中,也不需要转义。
括号需要前后都转义 /\(123\)/
^ $ . * + ? | \ /等字符,只要不在字符组内,都需要转义
正则表达式的运行步骤:
1. 编译
2. 设定起始位置
3. 尝试匹配
4. 匹配失败的话, 从下一位开始继续第3步
5. 最终结果: 匹配成功或失败
A. 使用具体型字符组来代替通配符,来消除回溯
B. 使用非捕获分组
因为括号的作用之一是,捕获分组和分支里的数据, 保存到内存中
当我们不需要使用分组引用和反向引用时, 可以使用非捕获分组
/^[+-]?(\d+\.\d+|\.\d+)$/
修改成
/^[+-]?(?:\d+\.\d+|\.\d+)$/
C. 独立出确定字符
如: /a++/ => /aa*/
D. 提取分支公共部分
如: /^abc|^def/ => /^(?:abc|def)/
/this|that/ => /th(?:is|at)/
E. 减少分支的数量,减少它们的范围
如: /red|read/ => /rea?d/
正则表达式案例:
通过className获取元素
function getElementsByClassName(className){// 获取页面中所有的标签元素var elements = document.getElementsByTagName('*');var reg = new RegExp("(^|\\s)" + className + "(\\s|$)");var result = [];for (var i = 0; i < elements.length; i++){var element = elements[i];if( reg.test(element.className)){result.push(element);}}return result; } console.log( getElementsByClassName('item') ); // [a.item, div.item, p.item, ...]
去掉字符串首尾空格
// 实现字符串的 trim 函数,去除字符串两边的空格。 String.prototype.trim = function () {// 方式一:将匹配到的每一个结果都用''替换return this.replace(/(^\s+)|(\s+$)/g, function(){return '';});// 方式二:和方式一的原理相同return this.replace(/(^\s+)|(\s+$)/g, '');// 方式三: 匹配整个字符串, 用引用来提取相应的数据return this.replace(/^\s*(.*?)\s*$/g, "$1"); }; " Miss You! ".trim(); // "Miss You!"
提取浏览器URL中的参数名和值,生成key/value对象
// 把"http://www.baidu.com/?name=yuix&id=123456" // 生成 {"name": "yuxi", "id": 123456}function getUrlParamsObj(){var obj = {};// 获取URL的参数部分var params = window.location.search.substr(1);// [^&=]+ 表是不含&或=的连续字符, 加上() 就是提取对应字符串var reg = /([^&=]+)=([^&=]*)/gi;params.replace(reg, function(rs, $1, $2){obj[$1] = decodeURIComponent($2);});return obj; }
扩展typeof, 包含引用类型的具体类型
function getDataType(obj) {var str = Object.prototype.toString.call(obj);var reg = /\[object\s(\w+)\]/;str = str.replace(reg, '$1'); // [object Xxx]return str.toLowerCase();// number、string、array、object、null、undefined、boolean } getDataType(1); // "number" getDataType("1"); // "string" getDataType([]); // "array" getDataType({}); // "object" getDataType(null); // "null" getDataType(undefined); // "undefined" getDataType(false); // "boolean"
在字符串指定位置插入新字符串
String.prototype.insetAt = function(str, offset){offset = offset + 1;// 使用RegExp()构造函数创建正则表达式var reg = new RegExp("(^.{"+offset+"})"); // /^.{3}/return this.replace(reg, '$1' + str); } "abcd".insetAt('2018', 2); // 在第二个字符后面插入2018 // "abc2018d"
将手机号13551209931转成135****9931
function formatTel(tel){tel += '';var reg = /(\d{3})(\d{4})(\d{4})/;// 方式一return tel.replace(reg, function(rs, $1, $2, $3){return $1 + '****' + $3;});// 方式二return tel.replace(reg, "$1****$3"); } formatTel("13551209931"); // "135****9931"
转载于:https://www.cnblogs.com/yuxi2018/p/9586168.html
[记录] JavaScript 中的正则表达式相关推荐
- 52 JavaScript中的正则表达式
技术交流QQ群:1027579432,欢迎你的加入! 欢迎关注我的微信公众号:CurryCoder的程序人生 1.什么是正则表达式 正则表达是(regular expression)是用于匹配字符串中 ...
- 十、JavaScript中的正则表达式(六)
@Author:Runsen @Date:2020/5/26 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严重,专业排 ...
- Javascript中使用正则表达式进行数据验证
Javascript中使用正则表达式进行数据验证 <script language="javascript"> function checkMobile(mobile ...
- JavaScript中的正则表达式详解
正则表达式(Regular Expression)是一门简单语言的语法规范,是强大.便捷.高效的文本处理工具,它应用在一些方法中,对字符串中的信息实现查找.替换和提取操作. 正则表达式在人们的印象中可 ...
- qq号的正则表达式html,JavaScript中的正则表达式使用及验证qq号码的正则
废话不多说了,直接给大家贴正则表达式代码了. function myValid() { var errorMsg = ""; var res = true; //拿到要验证的值. ...
- javascript中的正则表达式学习
一.前言 关于正则表达式自身的语法这里不做过多介绍(详情可参见http://www.php100.com/manual/unze.html),这里仅仅解释javascript中和正则表达式相关的几个方 ...
- 【一次搞懂】JavaScript中的正则表达式
一.什么是正则表达式 正则表达式的概念: 计算机科学的一个概念.正则表达式通常被用来检索.替换那些符合某个模式(规则)的文本 在JS中,正则表达式属于对象的一种: typeof /\d+/ " ...
- javascript中的正则表达式语法
正则表达式对象用来规范一个规范的表达式(也就是表达式符不符合特定的要求,比如是不是Email地址格式等),它具有用来检查给出的字符串是否符合规则的属性和方法.除此之外,你用RegExp构造器建立的个别 ...
- JavaScript中的正则表达式解析
正则表达式(regular expression)对象包含一个正则表达式模式(pattern).它具有用正则表达式模式去匹配或代替一个字符串(string)中特定字符(或字符集合)的属性(proper ...
最新文章
- hdu 模拟 贪心 4550
- 微信小程序实现web端锚点功能
- CVPR 2018 LSART:《Learning Spatial-Aware Regressions for Visual Tracking》论文笔记
- Pixhawk代码分析-姿态解算篇D
- hdu 1078 记忆化搜索
- 洛谷 P1816 忠诚 ST函数
- windows组件向导里没有internet 信息服务(iis) 的解决办法
- C++学习之路 | PTA乙级—— 1003 我要通过! (20分)(精简)
- python定义空数组_在numpy数组中设置空值
- c语言学生管理系统常见问题,关于C语言学生管理系统问题
- Web服务器常用设置
- LeetCode 135. 分发糖果(贪心算法)
- VXLAN配置实例(五)——云计算数据中心访问公司外部站点典型配置实例(超级超级难的网络配置!!!)
- java给数组排序_java数组如何排序
- 干货分享 | 全文 40000 字,最强(全) Matplotlib 实操指南
- 编写函数求区间[200,3000]中所有的回文数, 回文数是正读和反读都是一样的数
- 责任心与态度比技术更重要
- python xmind转excel 知乎_XMind: ZEN 重磅更新!新增导出Word/Excel,自定义快捷键和其他...
- 计算机90学时培训小结,90学时培训总结
- 浅谈巫师2的战斗难度策略
热门文章
- GeneXus学习记录——Transaction
- Lambda 表达式Demoo
- Qt屏幕的尺寸及屏幕分辨率
- weblogic BEA-170011
- vs编译错误:在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include stdafx.h”?
- 动作捕捉技术在四足仿生机器人研究中的应用
- 计算机文档xsl,跟我学XSL(一)——第一个XML文档
- xsl:apply-templates和xsl:call-template的区别
- FTP主动模式和被动模式!
- 正点原子linux驱动教程,正点原子 手把手教你学Linux之驱动开发篇