一次性搞懂JavaScript正则表达式之语法

本文是『horseshoe·Regex专题』系列文章之一,后续会有更多专题推出
GitHub地址:https://github.com/veedrin/horseshoe
博客地址(文章排版真的很漂亮):https://veedrin.com
如果觉得对你有帮助,欢迎来GitHub点Star或者来我的博客亲口告诉我
名余曰正则兮,字余曰灵均。

Regular Expressions翻译成中文叫正则表达式。也不知道是谁翻译过来的,听起来就很严肃。似乎翻译成通用表达式更能传达其精髓,如果你不怕梦见屈原的话。

为什么叫通用表达式?因为它有一套和编程语言无关的文本匹配规则。很多语言都实现了正则表达式的文本匹配引擎,只不过在功能集合上略有不同。

我们要记住的是三点:

其一,正则表达式是用来提取文本的。

其二,正则表达式的表达能力强大到令人发指。

其三,正则表达式的语法对初学者不友好。

另外,本专题只涉及JavaScript语言的正则表达式,其他语言的规则可能略有不同。

我还为各位读者准备了一副宣传语,应该能让你心动(点赞)吧?

学一门前端工具,几年就过时了。学正则表达式,受用一辈子。

普通字符

什么叫普通字符?

当我们写a的时候,我们指的就是a;当我们写的时候,我们指的就是

'hello ? regex'.match(/?/);
// ["?", index: 6, input: "hello ? regex", groups: undefined]

这就是普通字符,它在正则中的含义就是检索它本身。除了正则规定的部分字符外,其余的都是普通字符,包括各种人类语言,包括emoji,只要能够表达为字符串。

开始与结束

^字符的英文是caret,翻译成中文是脱字符。不要问我,又不是我翻译的。它在正则中属于元字符,通常代表的意义是文本的开始。说通常是因为当它在字符组中[^abc]另有含义。

什么叫文本的开始?就是如果它是正则主体的第一个符号,那紧跟着它的字符必须是被匹配文本的第一个字符。

'regex'.match(/^r/);
// ["r", index: 0, input: "regex", groups: undefined]

问题来了,如果^不是正则的第一个符号呢?

'regex'.match(/a^r/);
// null

所以呀,关于它有三点需要注意:

  • 作为匹配文本开始元字符的时候必须是正则主体的第一个符号,否则正则无效。
  • 它匹配的是一个位置,而不是具体的文本。
  • 它在其他规则中有另外的含义。

$字符与^正好相反。它代表文本的结束,并且没有其他含义(其实是有的,但不是在正则主体内)。同样,它必须是正则主体的最后一个符号。

'regex'.match(/x$/);
// ["x", index: 4, input: "regex", groups: undefined]

^$特殊的地方在于它匹配的是一个位置。位置不像字符,它看不见,所以更不容易理解。

转义

我们现在已经知道$匹配文本的结束位置,它是元字符。但是如果我想匹配$本身呢?匹配一个美元符号的需求再常见不过了吧。所以我们得将它贬为庶民。

\反斜杠就是干这个的。

'price: $3.6'.match(/\$[0-9]+\.[0-9]+$/);
// ["$3.6", index: 7, input: "price: $3.6", groups: undefined]

上面的例子有点超纲了,超纲的部分先不管。

你可以认为\也是一个元字符,它跟在另一个元字符后面,就能还原它本来的含义。

如果有两个\呢?那就是转义自身了。如果有三个\呢?我们得分成两段去理解。以此类推。

普通字符前面跟了一个\是什么效果?首先它们是一个整体,然后普通字符转义后还是普通字符。

带反斜杠的元字符

一般来说,普通字符前面带反斜杠还是普通字符,但是有一些普通字符,带反斜杠后反而变成了元字符。

要怪只能怪计算机领域的常用符号太少了。

元字符含义
b匹配一个单词边界(boundary)
B匹配一个非单词边界
d匹配一个数字字符(digit)
D匹配一个非数字字符
s匹配一个空白字符(space)
S匹配一个非空白字符
w匹配一个字母或者一个数字或者一个下划线(word)
W匹配一个字母、数字和下划线之外的字符

你这么聪明,肯定一眼就看出来,大写代表反义。对,就是这么好记。

b元字符

\b匹配的也是一个位置,而不是一个字符。单词和空格之间的位置,就是所谓单词边界。

'hello regex'.match(/\bregex$/);
// ["regex", index: 6, input: "hello regex", groups: undefined]
'hello regex'.match(/\Bregex$/);
// null

所谓单词边界,对中文等其他语言是无效的。

'jiangshuying gaoyuanyuan huosiyan'.match(/\bgaoyuanyuan\b/);
// ["gaoyuanyuan", index: 13, input: "jiangshuying gaoyuanyuan huosiyan", groups: undefined]
'江疏影 高圆圆 霍思燕'.match(/\b高圆圆\b/);
// null

所以\b翻译一下就是^\w|\w$|\W\w|\w\W

d元字符

\d匹配一个数字,注意,这里的数字不是指JavaScript中的数字类型,因为文本全是字符串。它指的是代表数字的字符。

'123'.match(/\d/);
// ["1", index: 0, input: "123", groups: undefined]

s元字符

\s匹配一个空白字符。

这里需要解释一下什么是空白字符。

空白字符不是空格,它是空格的超集。很多人说它是\f\n\r\t\v的总和,其中\f是换页符,\n是换行符,\r是回车符,\t是水平制表符,\v是垂直制表符。是这样么?

'a b'.match(/\w\s\w/);
// ["a b", index: 0, input: "a b", groups: undefined]
'a b'.match(/\w\f\w/);
// null
'a b'.match(/\w\n\w/);
// null
'a b'.match(/\w\r\w/);
// null
'a b'.match(/\w\t\w/);
// null
'a b'.match(/\w\v\w/);
// null
'a b'.match(/\w \w/);
// ["a b", index: 0, input: "a b", groups: undefined]

这样说的人,明显是没有做过实验。其实正确的写法是空格\f\n\r\t\v的总和,集合里面包含一个空格,可千万别忽略了。诶,难道空格在正则中的写法就是空一格么,是的,就是这样随意。

这个集合中很多都是不可打印字符,估计只有\n是我们的老朋友。所以,如果不需要区分空格和换行的话,那就大胆的用\s吧。

w元字符

\w匹配一个字母或者一个数字或者一个下划线。为什么要将它们放一起?想一想JavaScript中的变量规则,包括很多应用的用户名都只能是这三样,所以把它们放一起挺方便的。

不过要注意,字母指的是26个英文字母,其他的不行。

'正则'.match(/\w/);
// null

负阴抱阳

如果我们将大写和小写的带反斜杠的元字符组合在一起,就能匹配任何字符。是的,不针对任何人。

'@regex'.match(/[\s\S]/);
// ["@", index: 0, input: "@regex", groups: undefined]

方括号的含义我们先按下不表。

道生一

.在正则中的含义仙风道骨,它匹配换行符之外的任意单个字符。

如果文本不存在换行符,那么.[\b\B][\d\D][\s\S][\w\W]是等价的。

如果文本存在换行符,那么(.|\n)[\b\B][\d\D][\s\S][\w\W]是等价的。

'@regex'.match(/./);
// ["@", index: 0, input: "@regex", groups: undefined]

量词

前面我们一直在强调,一个元字符只匹配一个字符。即便强大如.它也只能匹配一个。

那匹配gooooogle的正则是不是得写成/gooooogle/呢?

正则冷笑,并向你发射一个蔑视。

如果匹配的模式有重复,我们可以声明它重复的次数。

量词含义
?重复零次或者一次
+重复一次或者多次,也就是至少一次
*重复零次或者多次,也就是任意次数
{n}重复n次
{n,}重复n次或者更多次
{n,m}重复n次到m次之间的次数,包含n次和m次

有三点需要注意:

  • ?在诸如匹配http协议的时候非常有用,就像这样:/http(s)?/。它在正则中除了是量词还有别的含义,后面会提到。
  • 我们习惯用/.*/来匹配若干对我们没有价值的文本,它的含义是若干除换行符之外的字符。比如我们需要文本两头的格式化信息,中间是什么无所谓,它就派上用场了。不过它的性能可不好。
  • {n,m}之间不能有空格,空格在正则中是有含义的。

关于量词最令人困惑的是:它重复什么?

它重复紧贴在它前面的某个集合。第一点,必须是紧贴在它前面;第二点,重复一个集合。最常见的集合就是一个字符,当然正则中有一些元字符能够将若干字符变成一个集合,后面会讲到。

'gooooogle'.match(/go{2,5}gle/);
// ["gooooogle", index: 0, input: "gooooogle", groups: undefined]

如果一个量词紧贴在另一个量词后面会怎样?

'gooooogle'.match(/go{2,5}+gle/);
// Uncaught SyntaxError: Invalid regular expression: /go{2,5}+gle/: Nothing to repeat

贪婪模式与非贪婪模式

前面提到量词不能紧跟在另一个量词后面,马上要??打脸了。

'https'.match(/http(s)?/);
// ["https", "s", index: 0, input: "https", groups: undefined]
'https'.match(/http(s)??/);
// ["http", undefined, index: 0, input: "https", groups: undefined]

然而,我的脸是这么好打的?

紧跟在?后面的?它不是一个量词,而是一个模式切换符,从贪婪模式切换到非贪婪模式。

贪婪模式在正则中是默认的模式,就是在既定规则之下匹配尽可能多的文本。因为正则中有量词,它的重复次数可能是一个区间,这就有了取舍。

紧跟在量词之后加上?就可以开启非贪婪模式。怎么省事怎么来。

这里的要点是,?必须紧跟着量词,否则的话它自己就变成量词了。

字符组

正则中的普通字符只能匹配它自己。如果我要匹配一个普通字符,但是我不确定它是什么,怎么办?

'grey or gray'.match(/gr[ae]y/);
// ["grey", index: 0, input: "grey or gray", groups: undefined]

方括号在正则中表示一个区间,我们称它为字符组。

首先,字符组中的字符集合只是所有的可选项,最终它只能匹配一个字符。

然后,字符组是一个独立的世界,元字符不需要转义。

'$'.match(/[$&@]/);
// ["$", index: 0, input: "$", groups: undefined]

最后,有两个字符在字符组中有特殊含义。

^在字符组中表示取反,不再是文本开始的位置了。

'regex'.match(/[^abc]/);
// ["r", index: 0, input: "regex", groups: undefined]

如果我就要^呢?前面已经讲过了,转义。

-本来是一个普通字符,在字符组中摇身一变成为连字符。

'13'.match(/[1-9]3/);
// ["13", index: 0, input: "13", groups: undefined]

连字符的意思是匹配范围在它的左边字符和右边字符之间。

如果我这样呢?

'abc-3'.match(/[0-z]/);
// ["a", index: 0, input: "abc-3", groups: undefined]
'xyz-3'.match(/[0-c]/);
// ["3", index: 4, input: "xyz-3", groups: undefined]
'xyz-3'.match(/[0-$]/);
// Uncaught SyntaxError: Invalid regular expression: /[0-$]/: Range out of order in character class

发现什么了没有?只有两种字符是可以用连字符的:英文字母和数字。而且英文字母可以和数字连起来,英文字母的顺序在后面。这和扑克牌1 2 3 4 5 6 7 8 9 10 J Q K是一个道理。

捕获组与非捕获组

我们已经知道量词是怎么回事了,我们也知道量词只能重复紧贴在它前面的字符。

如果我要重复的是一串字符呢?

'i love you very very very much'.match(/i love you very +much/);
// null
'i love you very very very much'.match(/i love you v+e+r+y+ +much/);
// null

这样肯定是不行的。是时候请圆括号出山了。

'i love you very very very much'.match(/i love you (very )+much/);
// ["i love you very very very much", "very ", index: 0, input: "i love you very very very much", groups: undefined]

圆括号的意思是将它其中的字符集合打包成一个整体,然后量词就可以操作这个整体了。这和方括号的效果是完全不一样的。

而且默认的,圆括号的匹配结果是可以捕获的。

正则内捕获

现在我们有一个需求,匹配<div>标签。

'<div>hello regex</div>'.match(/<div>.*<\/div>/);
// ["<div>hello regex</div>", index: 0, input: "<div>hello regex</div>", groups: undefined]

这很简单。但如果我要匹配的是任意标签,包括自定义的标签呢?

'<App>hello regex</App>'.match(/<([a-zA-Z]+)>.*<\/\1>/);
// ["<App>hello regex</App>", "App", index: 0, input: "<App>hello regex</App>", groups: undefined]

这时候就要用到正则的捕获特性。正则内捕获使用\数字的形式,分别对应前面的圆括号捕获的内容。这种捕获的引用也叫反向引用

我们来看一个更复杂的情况:

'<App>hello regex</App><p>A</p><p>hello regex</p>'.match(/<((A|a)pp)>(hello regex)+<\/\1><p>\2<\/p><p>\3<\/p>/);
// ["<App>hello regex</App><p>A</p><p>hello regex</p>", "App", "A", "hello regex", index: 0, input: "<App>hello regex</App><p>A</p><p>hello regex</p>", groups: undefined]

如果有嵌套的圆括号,那么捕获的引用是先递归的,然后才是下一个顶级捕获。所谓深度优先。

正则外捕获

'@abc'.match(/@(abc)/);
// ["@abc", "abc", index: 0, input: "@abc", groups: undefined]
RegExp.$1;
// "abc"

没错,RegExp就是构造正则的构造函数。如果有捕获组,它的实例属性$数字会显示对应的引用。

如果有多个正则呢?

'@abc'.match(/@(abc)/);
// ["@abc", "abc", index: 0, input: "@abc", groups: undefined]
'@xyz'.match(/@(xyz)/);
// ["@xyz", "xyz", index: 0, input: "@xyz", groups: undefined]
RegExp.$1;
// "xyz"

RegExp构造函数的引用只显示最后一个正则的捕获。

另外还有一个字符串实例方法也支持正则捕获的引用,它就是replace方法。

'hello **regex**'.replace(/\*{2}(.*)\*{2}/, '<strong>$1</strong>');
// "hello <strong>regex</strong>"

实际上它才是最常用的引用捕获的方式。

捕获命名

这是ES2018的新特性。

使用\数字引用捕获必须保证捕获组的顺序不变。现在开发者可以给捕获组命名了,有了名字以后,引用起来更加确定。

'<App>hello regex</App>'.match(/<(?<tag>[a-zA-Z]+)>.*<\/\k<tag>>/);
// ["<App>hello regex</App>", "App", index: 0, input: "<App>hello regex</App>", groups: {tag: "App"}]

在捕获组内部最前面加上?<key>,它就被命名了。使用\k<key>语法就可以引用已经命名的捕获组。

是不是很简单?

通常情况下,开发者只是想在正则中将某些字符当成一个整体看待。捕获组很棒,但是它做了额外的事情,肯定需要额外的内存占用和计算资源。于是正则又有了非捕获组的概念。

'@abc'.match(/@(abc)/);
// ["@abc", "abc", index: 0, input: "@abc", groups: undefined]
'@abc'.match(/@(?:abc)/);
// ["@abc", index: 0, input: "@abc", groups: undefined]

只要在圆括号内最前面加上?:标识,就是告诉正则引擎:我只要这个整体,不需要它的引用,你就别费劲了。从上面的例子也可以看出来,match方法返回的结果有些许不一样。

个人观点:我觉得正则的捕获设计应该反过来,默认不捕获,加上?:标识后才捕获。因为大多数时候开发者是不需要捕获的,但是它又懒得加?:标识,会有些许性能浪费。

分支

有时候开发者需要在正则中使用或者

'高圆圆'.match(/陈乔恩|高圆圆/);
// ["高圆圆", index: 0, input: "高圆圆", groups: undefined]

|就代表或者。字符组其实也是一个多选结构,但是它们俩有本质区别。字符组最终只能匹配一个字符,而分支匹配的是左边所有的字符或者右边所有的字符。

我们来看一个例子:

'我喜欢高圆圆'.match(/我喜欢陈乔恩|高圆圆/);
// ["高圆圆", index: 3, input: "我喜欢高圆圆", groups: undefined]

因为|是将左右两边一切两半,然后匹配左边或者右边。所以上面的正则显然达不到我们想要的效果。这个时候就需要一个东西来缩小分支的范围。诶,你可能已经想到了:

'我喜欢高圆圆'.match(/我喜欢(?:陈乔恩|高圆圆)/);
// ["我喜欢高圆圆", index: 0, input: "我喜欢高圆圆", groups: undefined]

没错,就是圆括号。

零宽断言

正则中有一些元字符,它不匹配字符,而是匹配一个位置。比如之前提到的^$^的意思是说这个位置应该是文本开始的位置。

正则还有一些比较高级的匹配位置的语法,它匹配的是:在这个位置之前或之后应该有什么内容。

零宽(zero-width)是什么意思?指的就是它匹配一个位置,本身没有宽度。

断言(assertion)是什么意思?指的是一种判断,断言之前或之后应该有什么或应该没有什么。

零宽肯定先行断言

所谓的肯定就是判断有什么,而不是判断没有什么。

而先行指的是向前看(lookahead),断言的这个位置是为前面的规则服务的。

语法很简单:圆括号内最左边加上?=标识。

'CoffeeScript JavaScript javascript'.match(/\b\w{4}(?=Script\b)/);
// ["Java", index: 13, input: "CoffeeScript JavaScript javascript", groups: undefined]

上面匹配的是四个字母,这四个字母要满足以下条件:紧跟着的应该是Script字符串,而且Script字符串应该是单词的结尾部分。

所以,零宽肯定先行断言的意思是:现在有一段正则语法,用这段语法去匹配给定的文本。但是,满足条件的文本不仅要匹配这段语法,紧跟着它的必须是一个位置,这个位置又必须满足一段正则语法。

说的再直白点,我要匹配一段文本,但是这段文本后面必须紧跟着另一段特定的文本。零宽肯定先行断言就是一个界碑,我要满足前面和后面所有的条件,但是我只要前面的文本。

我们来看另一种情况:

'CoffeeScript JavaScript javascript'.match(/\b\w{4}(?=Script\b)\w+/);
// ["JavaScript", index: 13, input: "CoffeeScript JavaScript javascript", groups: undefined]

上面的例子更加直观,零宽肯定先行断言已经匹配过Script一次了,后面的\w+却还是能匹配Script成功,足以说明它的零宽特性。它为紧贴在它前面的规则服务,并且不影响后面的匹配规则。

零宽肯定后行断言

先行是向前看,那后行就是向后看(lookbehind)咯。

语法是圆括号内最左边加上?<=标识。

'演员高圆圆 将军霍去病 演员霍思燕'.match(/(?<=演员)霍\S+/);
// ["霍思燕", index: 14, input: "演员高圆圆 将军霍去病 演员霍思燕", groups: undefined]

一个正则可以有多个断言:

'演员高圆圆 将军霍去病 演员霍思燕'.match(/(?<=演员)霍.+?(?=\s|$)/);
// ["霍思燕", index: 14, input: "演员高圆圆 将军霍去病 演员霍思燕", groups: undefined]

零宽否定先行断言

肯定是判断有什么,否定就是判断没有什么咯。

语法是圆括号内最左边加上?!标识。

'TypeScript Perl JavaScript'.match(/\b\w{4}(?!Script\b)/);
// ["Perl", index: 11, input: "TypeScript Perl JavaScript", groups: undefined]

零宽否定后行断言

语法是圆括号最左边加上?<!标识。

'演员高圆圆 将军霍去病 演员霍思燕'.match(/(?<!演员)霍\S+/);
// ["霍去病", index: 8, input: "演员高圆圆 将军霍去病 演员霍思燕", groups: undefined]

修饰符

正则表达式除了主体语法,还有若干可选的模式修饰符。

写法就是将修饰符安插在正则主体的尾巴上。比如这样:/abc/gi

g修饰符

gglobal的缩写。默认情况下,正则从左向右匹配,只要匹配到了结果就会收工。g修饰符会开启全局匹配模式,找到所有匹配的结果。

'演员高圆圆 将军霍去病 演员霍思燕'.match(/(?<=演员)\S+/);
// ["高圆圆", index: 2, input: "演员高圆圆 将军霍去病 演员霍思燕", groups: undefined]
'演员高圆圆 将军霍去病 演员霍思燕'.match(/(?<=演员)\S+/g);
// ["高圆圆", "霍思燕"]

i修饰符

iignoreCase的缩写。默认情况下,/z/是无法匹配Z的,所以我们有时候不得不这样写:/[a-zA-Z]/i修饰符可以全局忽略大小写。

很多时候我们不在乎文本是大写、小写还是大小写混写,这个修饰符还是很有用的。

'javascript is great'.match(/JavaScript/);
// null
'javascript is great'.match(/JavaScript/i);
// ["javascript", index: 0, input: "javascript is great", groups: undefined]

m修饰符

mmultiline的缩写。这个修饰符有特定起作用的场景:它要和^$搭配起来使用。默认情况下,^$匹配的是文本的开始和结束,加上m修饰符,它们的含义就变成了行的开始和结束。

`
abc
xyz
`.match(/xyz/);
// ["xyz", index: 5, input: "↵abc↵xyz↵", groups: undefined]
`
abc
xyz
`.match(/^xyz$/);
// null
`
abc
xyz
`.match(/^xyz$/m);
// ["xyz", index: 5, input: "↵abc↵xyz↵", groups: undefined]

y修饰符

这是ES2015的新特性。

ysticky的缩写。y修饰符有和g修饰符重合的功能,它们都是全局匹配。所以重点在sticky上,怎么理解这个粘连呢?

g修饰符不挑食,匹配完一个接着匹配下一个,对于文本的位置没有要求。但是y修饰符要求必须从文本的开始实施匹配,因为它会开启全局匹配,匹配到的文本的下一个字符就是下一次文本的开始。这就是所谓的粘连。

'a bag with a tag has a mag'.match(/\wag/g);
// ["bag", "tag", "mag"]
'a bag with a tag has a mag'.match(/\wag/y);
// null
'bagtagmag'.match(/\wag/y);
// ["bag", index: 0, input: "bagtagmag", groups: undefined]
'bagtagmag'.match(/\wag/gy);
// ["bag", "tag", "mag"]

有人肯定发现了猫腻:你不是说y修饰符是全局匹配么?看上面的例子,单独一个y修饰符用match方法怎么并不是全局匹配呢?

诶,这里说来就话长了。

长话短说呢,就涉及到y修饰符的本质是什么。它的本质有二:

  • 全局匹配(先别着急打我)。
  • 从文本的lastIndex位置开始新的匹配。lastIndex是什么?它是正则表达式的一个属性,如果是全局匹配,它用来标注下一次匹配的起始点。这才是粘连的本质所在。

不知道你们发现什么了没有:lastIndex是正则表达式的一个属性。而上面例子中的match方法是作用在字符串上的,都没有lastIndex属性,休怪人家工作不上心。

const reg = /\wag/y;
reg.exec('bagtagmag');
// ["bag", index: 0, input: "bagtagmag", groups: undefined]
reg.exec('bagtagmag');
// ["tag", index: 3, input: "bagtagmag", groups: undefined]
reg.exec('bagtagmag');
// ["mag", index: 6, input: "bagtagmag", groups: undefined]

咱们换成正则方法exec,多次执行,正则的lastIndex在变,匹配的结果也在变。全局匹配无疑了吧。

s修饰符

这是ES2018的新特性。

s不是dotAll的缩写。s修饰符要和.搭配使用,默认情况下,.匹配除了换行符之外的任意单个字符,然而它还没有强大到无所不能的地步,所以正则索性给它开个挂。

s修饰符的作用就是让.可以匹配任意单个字符。

ssingleline的缩写。

`
abc
xyz
`.match(/c.x/);
// null
`
abc
xyz
`.match(/c.x/s);
// ["c↵x", index: 3, input: "↵abc↵xyz↵", groups: undefined]

u修饰符

这是ES2015的新特性。

uunicode的缩写。有一些Unicode字符超过一个字节,正则就无法正确的识别它们。u修饰符就是用来处理这些不常见的情况的。

'?'.match(/^.$/);
// null
'?'.match(/^.$/u);
// ["?", index: 0, input: "?", groups: undefined]

?,与同义。

笔者对Unicode认识尚浅,这里不过多展开。

本文是『horseshoe·Regex专题』系列文章之一,后续会有更多专题推出
GitHub地址:https://github.com/veedrin/horseshoe
博客地址(文章排版真的很漂亮):https://veedrin.com
如果觉得对你有帮助,欢迎来GitHub点Star或者来我的博客亲口告诉我

Regex专题一览

? 语法

? 方法

? 引擎

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

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

相关文章

dbeaver导出表结构和数据_mall数据库表结构概览

mall是一套电商系统&#xff0c;后台系统主要包括商品管理、订单管理、营销管理(运营管理促销管理)、内容管理、用户管理等模块&#xff0c;本文主要对这些模块的数据库表结构及功能做大概的介绍。商品管理数据库表结构功能结构订单管理数据库表结构功能结构营销管理数据库表结…

arima模型 p q d 确定_自回归移动平均模型(ARMA)

自回归模型&#xff08;AR&#xff09;&#xff1a;①描述当前值和历史值之间的关系&#xff0c;用变量自身的历史时间数据对自身进行预测。②自回归模型必须满足平稳性的要求。③移动平均模型&#xff08;MA&#xff09;关注的是自回归模型中的误差项的累加。移动平均法能有效…

Mysql闪回工具之binlog2sql的原理及其使用

生产上误删数据、误改数据的现象也是时常发生的现象&#xff0c;作为运维这时候就需要出来补锅了&#xff0c;最开始的做法是恢复备份&#xff0c;然后从中找到需要的数据再进行修复&#xff0c;但是这个时间太长了&#xff0c;对于大表少数数据的修复来讲&#xff0c;动作太大…

禅道11.0windows本机安装

为了验证禅道的某个功能&#xff0c;需要用到生产上的数据&#xff0c;又不能在生产上进行。只能在本地搭建一套禅道&#xff0c;还原生产的数据到本地。 1.下载禅道 生产上用的是禅道11.0&#xff0c;数据库是11.0版本的数据库&#xff0c;为了更好兼容&#xff0c;下载禅道…

createtrackbar函数_【3】OpenCV图像处理模块(10)inRange函数实现阈值化,HSV图像分割...

本节使用inRange函数来实现阈值化。跟前面的阈值化方法一样&#xff0c;只不过在实现时用阈值范围来替代固定阈值。本节还提供了一种物体检测的手段&#xff0c;用基于像素值范围的方法&#xff0c;在HSV色彩空间检测物体。HSV色彩空间HSV&#xff08;hue&#xff0c;saturatio…

PPT取消自动播放

选中PPT页面&#xff0c;点击“切换”&#xff0c;检查下“设置自动换片时间”&#xff0c;如果勾选了&#xff0c;则去掉。

自动驾驶芯片_盘点全球自动驾驶芯片“战场”参与者

据了解&#xff0c;目前出货量最大的驾驶辅助芯片厂商Mobileye、Nvidia形成“双雄争霸”局面&#xff0c;Xilinx则在FPGA的路线上进军&#xff0c;Google、地平线、寒武纪向专用领域AI芯片发力&#xff0c;国内四维图新、全志科技、森国科(国科微)在自动驾驶芯片领域积极布局。…

word文档页码不连续怎么弄

页码不连续是因为在不连续页码的两页之间有分隔符。 第一步&#xff1a;搜索分节符 第二步&#xff1a;看页码与页面是否一致 wps的左下角 如果不一致&#xff0c;则第三步 第三步&#xff1a;设置页码&#xff1a;“继续上一页编码”

java多张图片合成一张_1分钟学会“全景照片”拍摄技巧,从单反拍摄到PS合成,收藏备用...

作为一名摄影爱好者&#xff0c;您知道如何才能快速拍出一张全景照片&#xff0c;同时保证高画质和照片不畸变&#xff1f;比如下面的2张图片&#xff1a;要想得到这样的全景照片&#xff0c;千万不要通过后期裁剪&#xff0c;否则清晰度肯定会大打折扣&#xff01;其实&#x…

Chrome查看cookie

不同版本的Chrome查看cookie的入口位置不同&#xff0c;这里介绍个通用的方法。 1.进入设置页 2.搜索cookie 3.进入“cookie....”&#xff0c;选择“查看所有......”

nginx 带宽_Nginx的Gzip功能

程序员自由之路 | 作者urlify.cn/eyuUVr | 来源什么是HTTP压缩有时候客户端和服务器之间会传输比较大的报文数据&#xff0c;这时候就占用较大的网络带宽和时长。为了节省带宽&#xff0c;加速报文的响应速速&#xff0c;可以将传输的报文数据先进行压缩&#xff0c;然后再进行…

分享朋友圈QQ空间需要哪些参数

shareTitle(分享标题 &#xff0c; shareDes(分享描述 &#xff0c; shareImg(分享图片地址&#xff0c; shareUrl(分享地址&#xff0c; shareType(分享类型&#xff0c;微信朋友&#xff1a;WEIXIN、微信朋友圈&#xff1a;WEIXIN_CIRCLE、QQ&#xff1a;QQ)

这一年多来,阿里Blink测试体系如何从0走向成熟?

2019独角兽企业重金招聘Python工程师标准>>> 摘要&#xff1a; 引言 Apache Flink是面向数据流处理和批处理的分布式开源计算框架&#xff0c;2016年阿里巴巴引入Flink框架&#xff0c;改造为Blink。2017年&#xff0c;阿里整合了所有流计算产品&#xff0c;决定以B…

system函数_自学C++基础教程【函数】

函数的概念一个函数由&#xff1a;函数的返回值类型、函数名、参数表、函数体 这4个部分组成。int Add( int _a , int _b ) {return _a _b; }该函数 Add 完成对两个整型数据的求和功能。函数的调用方式&#xff1a; 函数名&#xff08;参数表&#xff09;&#xff1b;…

宁波政务云资源的介绍与申请

介绍 如图所示&#xff1a; 宁波政务云分公共服务区与资源共享区。 公共服务区 公共服务区&#xff0c;一般部署允许互联网访问的系统&#xff0c;数据不敏感&#xff0c;不重要的&#xff0c;可对外开发的系统。 该区允许互联网访问&#xff0c;不允许访问资源共享区&…

python帮助文档在哪_python文档在哪里

对于Python中一些不清楚的模块&#xff0c;可以通过文档学习如何使用&#xff0c;但是python文档在哪里呢&#xff1f;这个问题我们可以使用Python命令进行查看。方法一 在python命令行输入以下内容help(time) # 很详细的模块文档 help(time.localtime()) # 很详细的函数文档 h…

政务云公共服务区与资源共享区数据交换的方式

上文《宁波政务云资源的介绍与申请》介绍过&#xff0c;公共服务区与资源共享区是不能互访的&#xff0c;只能是资源共享区单向访问公共服务区。 我有一项目&#xff0c;要能互联网访问&#xff0c;又要访问“宁波大数据共享平台”的接口&#xff0c;“宁波大数据共享平台”在…

Java程序员的IntelliJ IDEA使用教程

前言 博主是Java程序员&#xff0c;以前一直都用myeclipse来开发的&#xff0c;说实话感觉myeclipse毫无美感可言&#xff0c;后来经过同事介绍&#xff0c;认识了IDEA&#xff0c;一眼就相中了IDEA黑色的主题风格&#xff0c;自此就抛弃了旧爱myeclipse。当时还不懂IDEA功能上…

python中random函数用法_random函数的用法

展开全部 用法&#xff1a; 1、随2113机生成&#xff08;0,1&#xff09;之间的浮点数 random.random() 2、随机生成100-200的整数5261 random.randint(100,200) 3、随机产生范围为410210间隔为2的数 random.randrange(0,11,2) 注&#xff1a;这里输出&#xff08;0,2,4,6,8,10…

2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)

2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) 思路: A Exam 思路:水题 代码: #include<bits/stdc.h> using namespace std; int main(){int k;scanf("%d",&k);char s1[1010],s2[1010];scanf("%s%s",s1,s2);int same0;int ns…