Maison >interface Web >js tutoriel >Explication détaillée des expressions régulières JavaScript que tout le monde connaît

Explication détaillée des expressions régulières JavaScript que tout le monde connaît

黄舟
黄舟original
2017-03-14 15:06:351294parcourir

S'il s'agit d'un résumé d'expressions régulières , je préfère le considérer comme un manuel.

Trois méthodes principales de RegExp

RegExp dans cet article utilisent la syntaxe de quantité directe : /pattern/attributes. Il existe trois options pour les attributs, i, m et g. m (correspondance multiligne) n'est pas couramment utilisé et peut être omis directement, donc un modèle (modèle de correspondance) peut être exprimé comme suit :

var pattern = /hello/ig;

i (ignorer) signifie aucune distinction de taille Write (local search match), ce qui est relativement simple et ne sera pas décrit dans les exemples suivants g (global) signifie global (search match), c'est-à-dire ; , continuez à chercher après en avoir trouvé une, ce qui est relativement compliqué parmi les méthodes suivantes Sera spécialement présenté.

Comme ce sont les trois méthodes principales de RegExp, elles sont toutes au format pattern.test/exec/complie.

  • test

Fonction principale : détecte si la chaîne spécifiée contient une certaine sous-chaîne (ou un modèle correspondant) et renvoie vrai ou faux.

Les exemples sont les suivants :

var s = 'you love me and I love you';
var pattern = /you/;
var ans = pattern.test(s);
console.log(ans); // true

Si les attributs utilisent g, vous pouvez continuer la recherche, ce qui impliquera également l'attribut lastIndex (se référer à l'introduction de g en exécutable).

  • exec

Fonction principale : extraire la sous-chaîne requise (ou le modèle correspondant) dans la chaîne spécifiée et renvoyer un Tableau stocke les résultats correspondants ; s'il n'y en a pas, null est renvoyé. (Vous pouvez également écrire votre propre méthode pour boucler pour extraire toutes les données d'index ou celles spécifiées)

exec peut être considéré comme une version améliorée de test, car il peut non seulement détecter, mais extraire également directement les résultats après détection.

Un exemple est le suivant :

var s = 'you love me and I love you';
var pattern = /you/;
var ans = pattern.exec(s);
console.log(ans); // ["you", index: 0, input: "you love me and I love you"]
console.log(ans.index); // 0
console.log(ans.input); // you love me and I love you

Le résultat est très intéressant. Le 0ème élément de ce tableau est le texte qui correspond à l'expression régulière, le 1er élément est le texte qui correspond à la 1ère sous-expression de RegExpObject (le cas échéant) et le 2ème élément est le texte qui correspond au 2ème sous-expression de RegExpObject (le cas échéant), et ainsi de suite.

Qu'est-ce que « un texte qui correspond à une sous-expression » ? Regardez l'exemple suivant :

var s = 'you love me and I love you';
var pattern = /y(o?)u/;
var ans = pattern.exec(s);
console.log(ans);   // ["you", "o", index: 0, input: "you love me and I love you"]
console.log(ans.length) // 2

La soi-disant sous-expression est la chose à l'intérieur de () dans le modèle (pour plus de détails, veuillez vous référer à l'introduction des sous-expressions ci-dessous). En regardant la longueur du tableau dans l’exemple ci-dessus, elle est de 2 ! ! index et input ne sont que des attributs de tableau (la sortie ci-dessus dans chrome peut être trompeuse).

En plus des éléments du tableau et des propriétés de longueur, la méthode exec() renvoie deux propriétés. L'attribut index déclare la position du premier caractère du texte correspondant. L'attribut input stocke la chaîne récupérée string. On peut voir que lorsque appelle la méthode exec() de l'objet RegExp non global , le tableau renvoyé est le même que le tableau renvoyé en appelant la méthode String.match() .

Si vous utilisez le paramètre "g", exec() fonctionne comme suit (toujours l'exemple ci-dessus ps : si test utilise le paramètre g c'est similaire) :

  1. Trouvez le premier « vous » et stockez sa position

  2. Si vous exécutez à nouveau exec(), lancez la récupération à partir de la position stockée (lastIndex), recherchez le prochain « vous » et stockez-le Position

Lorsque RegExpObject est une expression régulière globale, le comportement de exec() est légèrement plus compliqué. Il commence à récupérer la chaîne chaîne au caractère spécifié par la propriété lastIndex de RegExpObject. Lorsque exec() trouve le texte qui correspond à une expression, il définit la propriété lastIndex de RegExpObject à la position à côté du dernier caractère du texte correspondant après la correspondance. Cela signifie que nous pouvons parcourir tout le texte correspondant dans une chaîne en appelant la méthode exec() à plusieurs reprises. Lorsque exec() ne trouve plus de texte correspondant, il renvoie null et réinitialise la propriété lastIndex à 0. L'attribut lastIndex est introduit ici, qui ne fonctionne que lorsqu'il est associé à g et test (ou g et exec). C'est un attribut de pattern, un entier , indiquant la position du caractère où commence la prochaine correspondance.

L'exemple est le suivant :

var s = 'you love me and I love you';
var pattern = /you/g;
var ans;
do {
  ans = pattern.exec(s);
  console.log(ans);
  console.log(pattern.lastIndex);
}
while (ans !== null)

Le résultat est le suivant :

Cela devrait être facile à comprendre Quand. il est bouclé pour la troisième fois, il est introuvable. Il a atteint « vous », donc null est renvoyé et la valeur lastIndex devient également 0.

如果在一个字符串中完成了一次模式匹配之后要开始检索新的字符串(仍然使用旧的pattern),就必须手动地把 lastIndex 属性重置为 0。

  • compile

主要功能:改变当前匹配模式(pattern)

这货是改变匹配模式时用的,用处不大,略过。详见JavaScript compile() 方法

String 四大护法

和RegExp三大方法分庭抗礼的是String的四大护法,四大护法有些和RegExp三大方法类似,有的更胜一筹。

既然是String家族下的四大护法,所以肯定是string在前,即str.search/match/replace/split形式。

既然是String的方法,当然参数可以只用字符串而不用pattern。

  • search

主要功能:搜索指定字符串中是否含有某子串(或者匹配模式),如有,返回子串在原串中的初始位置,如没有,返回-1。

是不是和test类似呢?test只能判断有木有,search还能返回位置!当然test()如果有需要能继续找下去,而search则会自动忽略g(如果有的话)。实例如下:

var s = 'you love me and I love you';
var pattern = /you/;
var ans = s.search(pattern);
console.log(ans);  // 0

话说和String的indexOf方法有点相似,不同的是indexOf方法可以从指定位置开始查找,但是不支持正则。

  • match

主要功能:和exec类似,从指定字符串中查找子串或者匹配模式,找到返回数组,没找到返回null

match是exec的轻量版,当不使用全局模式匹配时,match和exec返回结果一致;当使用全局模式匹配时,match直接返回一个字符串数组,获得的信息远没有exec多,但是使用方式简单。

实例如下:

var s = 'you love me and I love you';
console.log(s.match(/you/));    // ["you", index: 0, input: "you love me and I love you"]
console.log(s.match(/you/g));   // ["you", "you"]
  • replace

主要功能:用另一个子串替换指定字符串中的某子串(或者匹配模式),返回替换后的新的字符串  str.replace(‘搜索模式’,'替换的内容’)  如果用的是pattern并且带g,则全部替换;否则替换第一处。

实例如下:

var s = 'you love me and I love you';
console.log(s.replace('you', 'zichi')); // zichi love me and I love you
console.log(s.replace(/you/, 'zichi')); // zichi love me and I love you
console.log(s.replace(/you/g, 'zichi'));    // zichi love me and I love zichi

如果需要替代的内容不是指定的字符串,而是跟匹配模式或者原字符串有关,那么就要用到$了(记住这些和$符号有关的东东只和replace有关哦)。

怎么用?看个例子就明白了。

var s = 'I love you';
var pattern = /love/;
var ans = s.replace(pattern, '$`' + '$&' + "$'");
console.log(ans); // I I love you you

没错,’$`’ + ‘$&’ + “$’”其实就相当于原串了!

replace的第二个参数还能是函数,看具体例子前先看一段介绍:

注意:第一个参数是匹配到的子串,接下去是子表达式匹配的值,如果要用子表达式参数,则必须要有第一个参数(表示匹配到的串),也就是说,如果要用第n个参数代表的值,则左边参数都必须写出来。最后两个参数跟exec后返回的数组的两个属性差不多。

var s = 'I love you';
var pattern = /love/;
var ans = s.replace(pattern, function(a) {  // 只有一个参数,默认为匹配到的串(如还有参数,则按序表示子表达式和其他两个参数)
  return a.toUpperCase();
});
console.log(ans); // I LOVE you
  • split

主要功能:分割字符串

字符串分割成字符串数组的方法(另有数组变成字符串的join方法)。直接看以下例子:

var s = 'you love me and I love you';
var pattern = 'and';
var ans = s.split(pattern);
console.log(ans);   // ["you love me ", " I love you"]

如果你嫌得到的数组会过于庞大,也可以自己定义数组大小,加个参数即可:

var s = 'you love me and I love you';
var pattern = /and/;
var ans = s.split(pattern, 1);
console.log(ans);   // ["you love me "]

RegExp 字符

  • \s 任意空白字符 \S相反 空白字符可以是: 空格符 (space character) 制表符 (tab character) 回车符 (carriage return character) 换行符 (new line character) 垂直换行符 (vertical tab character) 换页符 (form feed character)

  • \b是正则表达式规定的一个特殊代码,代表着单词的开头或结尾,也就是单词的分界处。虽然通常英文的单词是由空格,标点符号或者换行来分隔的,但是\b并不匹配这些单词分隔字符中的任何一个,它只匹配一个位置。(和^ $ 以及零宽断言类似)

  • \w 匹配字母或数字或下划线   [a-z0-9A-Z_]完全等同于\w

贪婪匹配和懒惰匹配

什么是贪婪匹配?贪婪匹配就是在正则表达式的匹配过程中,默认会使得匹配长度越大越好。

var s = 'hello world welcome to my world';
var pattern = /hello.*world/;
var ans = pattern.exec(s);
console.log(ans)  // ["hello world welcome to my world", index: 0, input: "hello world welcome to my world"]

以上例子不会匹配最前面的Hello World,而是一直贪心的往后匹配。

那么我需要最短的匹配怎么办?很简单,加个‘?’即可,这就是传说中的懒惰匹配,即匹配到了,就不往后找了。

var s = 'hello world welcome to my world';
var pattern = /hello.*?world/;
var ans = pattern.exec(s);
console.log(ans)  // ["hello world", index: 0, input: "hello world welcome to my world"]

懒惰限定符(?)添加的场景如下:

子表达式

  • 表示方式

用一个小括号指定:

var s = 'hello world';
var pattern = /(hello)/;
var ans = pattern.exec(s);
console.log(ans);
  • 子表达式出现场景

在exec中数组输出子表达式所匹配的值:

var s = 'hello world';
var pattern = /(h(e)llo)/;
var ans = pattern.exec(s);
console.log(ans); // ["hello", "hello", "e", index: 0, input: "hello world"]

在replace中作为替换值引用

var s = 'hello world';
var pattern = /(h\w*o)\s*(w\w*d)/;
var ans = s.replace(pattern, '$2 $1')
console.log(ans); // world hello

后向引用 & 零宽断言

  • 子表达式的序号问题

简单地说:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。

复杂地说:分组0对应整个正则表达式实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号。可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权.

后向引用

如果我们要找连续两个一样的字符,比如要找两个连续的c,可以这样/c{2}/,如果要找两个连续的单词hello,可以这样/(hello){2}/,但是要在一个字符串中找连续两个相同的任意单词呢,比如一个字符串hellohellochinaworldworld,我要找的是hello和world,怎么找?

这时候就要用后向引用。看具体例子:

var s = 'hellohellochinaworldworld';
var pattern = /(\w+)\1/g;
var a = s.match(pattern);
console.log(a); // ["hellohello", "worldworld"]

这里的\1就表示和匹配模式中的第一个子表达式(分组)一样的内容,\2表示和第二个子表达式(如果有的话)一样的内容,\3 \4 以此类推。(也可以自己命名,详见参考文献)

或许你觉得数组里两个hello两个world太多了,我只要一个就够了,就又要用到子表达式了。因为match方法里是不能引用子表达式的值的,我们回顾下哪些方法是可以的?没错,exec和replace是可以的!

exec方式:

var s = 'hellohellochinaworldworld';
var pattern = /(\w+)\1/g;
var ans;
do {
  ans = pattern.exec(s);
  console.log(ans);
} while(ans !== null);

// result
// ["hellohello", "hello", index: 0, input: "hellohellochinaworldworld"] index.html:69
// ["worldworld", "world", index: 15, input: "hellohellochinaworldworld"] index.html:69
// null

如果输出只要hello和world,console.log(ans[1])即可。

replace方式:

var s = 'hellohellochinaworldworld';
var pattern = /(\w+)\1/g;
var ans = [];
s.replace(pattern, function(a, b) {
 ans.push(b);
});
console.log(ans);   // ["hello", "world"]

如果要找连续n个相同的串,比如说要找出一个字符串中出现最多的字符:

String.prototype.getMost = function() {
  var a = this.split('');
  a.sort();
  var s = a.join('');
  var pattern = /(\w)\1*/g;
  var a = s.match(pattern);
  a.sort(function(a, b) {
    return a.length < b.length;
  });
  var letter = a[0][0];
  var num = a[0].length;
  return letter + &#39;: &#39; + num;
}

var s = &#39;aaabbbcccaaabbbcccccc&#39;;
console.log(s.getMost()); // c: 9

如果需要引用某个子表达式(分组),请认准后向引用!

零宽断言

别被名词吓坏了,其实解释很简单。

它们用于查找在某些内容(但并不包括这些内容)之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言)

  • (?=exp)

零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。

// 获取字符串中以ing结尾的单词的前半部分
var s = &#39;I love dancing but he likes singing&#39;;
var pattern = /\b\w+(?=ing\b)/g;
var ans = s.match(pattern);
console.log(ans); // ["danc", "sing"]
  • (?!exp)

零宽度负预测先行断言,断言此位置的后面不能匹配表达式exp

// 获取第五位不是i的单词的前四位
var s = &#39;I love dancing but he likes singing&#39;;
var pattern = /\b\w{4}(?!i)/g;
var ans = s.match(pattern);
console.log(ans); // ["love", "like"]

javascript正则只支持前瞻,不支持后瞻((?<=exp)和(?

关于零宽断言的具体应用可以参考综合应用一节给字符串加千分符。

其他

  • 字符转义

因为某些字符已经被正则表达式用掉了,比如. * ( ) / \  [],所以需要使用它们(作为字符)时,需要用\转义

var s = &#39;http://www.cnblogs.com/zichi/&#39;;
var pattern = /http:\/\/www\.cnblogs\.com\/zichi\//;
var ans = pattern.exec(s);
console.log(ans); // ["http://www.cnblogs.com/zichi/", index: 0, input: "http://www.cnblogs.com/zichi/"]
  • 分支条件

如果需要匹配abc里的任意字母,可以用[abc],但是如果不是单个字母那么简单,就要用到分支条件。

分支条件很简单,就是用|表示符合其中任意一种规则。

var s = "I don&#39;t like you but I love you";
var pattern = /I.*(like|love).*you/g;
var ans = s.match(pattern);
console.log(ans); // ["I don&#39;t like you but I love you"]

答案执行了贪婪匹配,如果需要懒惰匹配,则:

var s = "I don&#39;t like you but I love you";
var pattern = /I.*?(like|love).*?you/g;
var ans = s.match(pattern);
console.log(ans); // ["I don&#39;t like you", "I love you"]

综合应用

  •  去除字符串首尾空格(replace)

String.prototype.trim = function() {
  return this.replace(/(^\s*)|(\s*$)/g, "");
};
var s = &#39;    hello  world     &#39;;
var ans = s.trim();
console.log(ans.length);    // 12
  • 给字符串加千分符(零宽断言)

String.prototype.getAns = function() {
  var pattern = /(?=((?!\b)\d{3})+$)/g;
  return this.replace(pattern, &#39;,&#39;);
}

var s = &#39;123456789&#39;;
console.log(s.getAns());  // 123,456,789
  • 找出字符串中出现最多的字符(后向引用)

String.prototype.getMost = function() {
  var a = this.split(&#39;&#39;);
  a.sort();
  var s = a.join(&#39;&#39;);
  var pattern = /(\w)\1*/g;
  var a = s.match(pattern);
  a.sort(function(a, b) {
    return a.length < b.length;
  });
  var letter = a[0][0];
  var num = a[0].length;
  return letter + &#39;: &#39; + num;
}

var s = &#39;aaabbbcccaaabbbcccccc&#39;;
console.log(s.getMost()); // c: 9

常用匹配模式(持续更新

  1.  只能输入汉字:/^[\u4e00-\u9fa5]{0,}$/

Résumé

  1. test : Vérifiez s'il existe une certaine sous-chaîne (ou un modèle correspondant) dans la chaîne spécifiée, renvoie vrai ou false ; effectuez une recherche de modèle globale si nécessaire.

  2. exec : Vérifiez s'il existe une certaine sous-chaîne (ou un modèle correspondant) dans la chaîne spécifiée, et si c'est le cas, renvoyez un tableau (les informations sur le tableau sont riches, veuillez vous référer à l'introduction ci-dessus), si null n'est pas renvoyé ; si nécessaire, une recherche globale peut être effectuée pour trouver les informations de toutes les sous-chaînes (ou modèles correspondants). Les informations contiennent la chaîne correspondant au. sous-expression dans le modèle correspondant.

  3. compile : Modifier le modèle dans l'expression régulière

  4. recherche : Vérifier le spécifié caractères Y a-t-il une certaine sous-chaîne (ou modèle correspondant) dans la chaîne ? Si tel est le cas, renvoie la position de départ de la sous-chaîne (ou modèle correspondant) dans la chaîne d'origine. Sinon, renvoie -1. La recherche globale n'est pas possible.

  5. match : Vérifiez s'il existe une certaine sous-chaîne (ou un modèle correspondant) dans la chaîne spécifiée. En mode non global, les informations renvoyées sont cohérentes avec exec. ; si vous effectuez une recherche globale, renvoie directement un tableau de chaînes. (Si vous n'avez pas besoin de plus d'informations sur chaque correspondance, il est recommandé d'utiliser match au lieu d'exec)

  6. replace : Vérifiez s'il existe une certaine sous-chaîne dans la chaîne spécifiée (ou le modèle correspondant), et remplacez-la par une autre sous-chaîne (la sous-chaîne peut être liée à la chaîne d'origine ou à la sous-chaîne recherchée) si g est activé, elle sera remplacée globalement, sinon seule la première sera remplacée ; remplacé. La méthode replace peut référencer la valeur correspondant à la sous-expression.

  7. split : divise la chaîne en utilisant un modèle spécifique et renvoie un tableau de chaînes ; exactement le contraire de la méthode de jointure de Array.

  8. Sous-expression : une expression régulière correspondante entre parenthèses, qui peut être référencée à l'aide d'une référence arrière, elle peut également être obtenue avec exec ou remplacer sa vraie valeur correspondante ; .

  9. Référence arrière : Référencez le groupe où se trouve la sous-expression.

  10. Assertion de largeur nulle : Un concept positionnel similaire à b ^ et $.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn