Muchos principiantes en front-end se sienten intimidados cuando se encuentran con expresiones regulares. Cuando comencé a aprender, básicamente me salté el capítulo sobre expresiones regulares. Excepto por copiar algunas expresiones regulares de uso común en Internet para la verificación de formularios, el resto del tiempo casi Nunca entendí cómo escribir una expresión regular.
Sin embargo, cuando realmente quise escribir una expresión regular adecuada para un negocio específico, descubrí que mi conocimiento de las expresiones regulares era realmente limitado. Así que aquí también utilicé un mapa mental para clasificar algunos puntos de conocimiento que debes conocer sobre las expresiones regulares.
¿Qué es una expresión regular?
Expresiones regulares, también conocidas como expresiones regulares. (Inglés: expresión regular, a menudo abreviada como expresión regular, expresión regular o RE en código), un concepto en informática. Las expresiones regulares se utilizan a menudo para recuperar y reemplazar texto que coincide con un determinado patrón (regla).
En el proceso de desarrollo de software, estamos más o menos expuestos a expresiones regulares. Para el front-end, las expresiones regulares no solo pueden verificar formularios, buscar y reemplazar texto, sino que también pueden usarse como analizadores de sintaxis, AST y editores. y otros campos.
expresión regular
representación directa
Las cantidades directas también se llaman literales y se escriben de la siguiente manera:
/^\d+$/g
Las expresiones regulares escritas en formato directo se convertirán en un nuevo RegExp
objeto cuando se ejecuten. Creo que es porque las variables directas no tienen la capacidad de llamar a métodos, solo cuando se convierten en objetos es posible llamar a métodos. Es por eso /^\d+$/.test()
.
Cuando utilice un objeto regular en un bucle lastIndex
para determinar la condición de terminación, asegúrese de no utilizar la escritura de expresiones regulares literales, de lo contrario, cada bucle lastIndex
se restablecerá a 0
Esto se debe a que cada vez que se ejecuta una expresión regular literal, se convertirá en una Por supuesto, los nuevos objetos se convertirán en RegExp
correspondientes .lastIndex
0
Notación de objetos RegExp
var pattern = new RegExp(/^\d+$/, 'g')
El primer parámetro puede aceptar una expresión regular literal o una cadena. Al pasar una cadena como primer parámetro, no es necesaria una barra al principio o al final. Si se utiliza un carácter especial en la cadena, \
debe ir \
precedido uno. \
, para evitar \
que se escape en la cadena.
"\s" === "s" // true
Las cadenas "\\s"
se pueden representar correctamente.\s
El segundo parámetro representa la bandera flags
. Las banderas aceptables son i
, g
, m
etc.
banderas banderas
i
Si la bandera está habilitada i
, las expresiones regulares se ejecutan sin distinguir entre mayúsculas y minúsculas.
/abc/i.test('abc')等价于/abc/i.test('ABC')
gramo
Si la bandera está habilitada g
, la expresión regular realizará una coincidencia global y no dejará de coincidir inmediatamente después de hacer coincidir un resultado hasta que no haya caracteres posteriores que coincidan con las reglas de coincidencia.
metro
Si la bandera está habilitada m
, la expresión regular realiza una coincidencia de varias líneas, que ^
puede coincidir con el comienzo de cada línea o el comienzo de toda la cadena, y $
puede coincidir con el final de cada línea o el final de toda la cadena.
/^\d+$/.test('123\n456') // false /^\d+$/m.test('123\n456') // true
Todavía puede coincidir con toda la cadena
/^\d+\n\d+$/m.test('123\n45') // true
calificador de posición
^
Coincide con el comienzo del personaje. Por ejemplo, si debe comenzar con un número, puedes escribir:
/^\d/
ps
El final del personaje coincidente. Por ejemplo, si debe terminar en un número, puedes escribir:
/\d$/
coincidencia de rango
[]
La coincidencia de rango se implementa mediante corchetes .
Los corchetes []
se utilizan para la coincidencia de rangos, que consiste en encontrar caracteres dentro de un rango determinado. Por ejemplo, [0-9]
significa hacer coincidir números, pero [a-z]
puede hacer coincidir cualquiera de los 26 caracteres desde las letras minúsculas de la a a la z.
Si desea hacer coincidir caracteres que no están entre corchetes, puede comenzar con entre corchetes ^
, por ejemplo [^0-9]
, para hacer coincidir caracteres que no sean dígitos, lo que equivale a \D
.
metacaracteres primarios
.
Coincide con \n
cualquier carácter, excepto los de nueva línea. Si desea hacer coincidir cualquier carácter, debe utilizar /[.\n]*/
.
\s
Coincide con cualquier carácter vacío, incluidos espacios, tabulaciones \t
, tabulaciones verticales \v
, avances de línea \n
, retornos de carro \r
y avances de formulario \f
. \s
Equivalente a [ \t\v\n\r\f]
, tenga en cuenta que hay un espacio en la primera posición entre corchetes.
Aquí también hablamos de la diferencia entre caracteres de avance de línea y retorno de carro:
- Salto de línea
\n
: mueve el cursor hacia abajo una línea sin regresar al principio de la línea. - Carácter de retorno de carro
\r
: el cursor regresa al principio de la línea sin una nueva línea.
\S
\S
Sí \s
, el conjunto inverso de y usando la relación inversa mutua de y, podemos hacer coincidir cualquier carácter, escrito de la siguiente manera \s
:\S
/[\s\S]/
\d
\d
Se utiliza para unir números, equivalente a [0-9]
.
\D
\D
Sí \d
, el conjunto inverso, es decir, hacer coincidir no números, es equivalente a [^0-9]
.
\w
\w
Se utiliza para hacer coincidir caracteres de palabras, incluidos , 0-9
y guión bajo , equivalente a .a-z
A-z
_
[A-Za-z0-9_]
\W
\W
Es \w
el conjunto inverso, utilizado para hacer coincidir caracteres que no son palabras, equivalente a [^A-Za-z0-9_]
.
\norte
\n
Es un carácter de salto de línea que se encuentra a menudo en el desarrollo y \s
se incluyen los mencionados anteriormente \n
. Por lo tanto, \n
los caracteres que pueden coincidir también deben \s
coincidir.
\b
\b
Se utiliza para hacer coincidir los límites de las palabras, es decir, el principio o el final de una palabra.
De hecho, al principio no entendí muy bien \b
su papel en las expresiones regulares .
Hasta que probé este caso yo mismo
Copiar código
'I love you'.match(/love/) 'Iloveyou'.match(/love/)
Ambas expresiones pueden coincidir con el resultado "love"
.
Pero a veces no queremos que dicha cadena 'Iloveyou'
coincida porque no tiene espacios entre palabras.
Entonces \b
tiene el significado de existencia. Mira el siguiente ejemplo:
Copiar código
'I love you'.match(/\blove\b/) 'Iloveyou'.match(/\blove\b/) // null
La primera expresión aún puede coincidir con el resultado normalmente, pero la segunda expresión no puede coincidir con el resultado, lo cual está en línea con nuestras expectativas.
Algunas personas pueden decir, entonces puedo usar espacios para hacer coincidir.
Copiar código
'I love you'.match(/ love /)
Los espacios \b
aún son un poco diferentes en este escenario, lo que se refleja match
en los resultados.
Si usa espacios para hacer coincidir, entonces match
el primer elemento en la matriz de resultados " love "
tiene espacios, sin embargo, muchas veces no queremos obtener espacios en los resultados, por lo que \b
el significado de existencia es más obvio.
\B
Lo \b
contrario, representa un límite sin palabras. En otras palabras, \B
cuando se utiliza la coincidencia, no puede haber espacios antes o después del carácter de destino.
Supongamos \B
primero, por ejemplo
/\Babc/.test('111 abc') // false
Supongamos \B
más tarde, por ejemplo.
/abc\B/.test('abc 111') // false
Personaje de escape\
Dado que muchos caracteres en las expresiones regulares tienen significados especiales, como,,,,,, si realmente desea que coincidan, debe agregar caracteres (
de )
escape .\
[
]
+
\
/\//.test('/'); // true
o |
La lógica de implementar OR es relativamente simple y está proporcionada por expresiones regulares |
.
Cabe señalar que |
lo que se separa es la subexpresión completa a su izquierda y derecha, no un solo carácter ordinario.
entonces,
/^ab|cd|ef$/.test('ab') // true
/^ab|cd|ef$/.test('cd') // true
/^ab|cd|ef$/.test('ace') // false
También tenga en cuenta que |
hay una prioridad de izquierda a derecha, por lo que si el de la izquierda coincide, el de la derecha se ignora, incluso si la coincidencia de la derecha parece más "perfecta".
/a|ab/.exec('ab')得到的结果是
["a", index: 0, input: "ab", groups: undefined]
cuantificador
?
Coincide con la subexpresión anterior cero o una vez
+
Coincide con la subexpresión anterior una o más veces
*
Coincide con la subexpresión anterior cero o cualquier momento
{Nuevo Méjico}
Coincide con el carácter ordinario o subexpresión anterior al menos n veces y como máximo m veces
{norte,}
Coincide con el carácter ordinario o subexpresión anterior al menos n veces
{norte}
Coincide con el carácter ordinario o subexpresión anterior n veces
avaro
La coincidencia codiciosa consiste en hacer coincidir tanto como sea posible. Si se pueden cumplir las condiciones de coincidencia, ocupará las reglas de coincidencia posteriores tanto como sea posible.
La coincidencia codiciosa es la opción predeterminada, como /\d?/
hacer coincidir 1
tantos números como sea posible /\d+/
y /\d*/
hacer coincidir tantos números como sea posible.
Por ejemplo,
'123456789'.match(/^(\d+)(\d{2,})$/)
En el resultado anterior, el primer elemento del grupo de captura es "1234567"
y el segundo elemento es "89"
.
¿Por qué esto es tan? Debido a \d+
que es una coincidencia codiciosa, combine tantas como sea posible. Si no hay una posterior \d{2,}
, el primer elemento en el grupo de captura será directamente "123456789"
. Pero debido a \d{2,}
la existencia de, \d+
salvará \d{2,}
las apariencias y cumplirá con sus condiciones mínimas, es decir, acertará 2 números y \d+
acertará 7 números por sí solo.
No codicioso
La coincidencia no codiciosa consiste en coincidir lo menos posible, generalmente agregando uno después del cuantificador ?
, para indicar la menor coincidencia posible, dejando la oportunidad para las reglas de coincidencia posteriores +
.*
?
Tomemos el ejemplo en modo codicioso y cambiémoslo ligeramente \d+
al modo no codicioso \d+?
.
'123456789'.match(/^(\d+?)(\d{2,})$/)
El primer elemento del grupo de captura es "1"
y el segundo se convierte en "23456789"
.
¿Por qué esto es tan? Porque en el modo no codicioso, habrá la menor cantidad de coincidencias posible, dejando oportunidades para las reglas de coincidencia posteriores.
Grupo
La agrupación es un artefacto muy útil en las expresiones regulares. ()
El contenido entre paréntesis es un grupo. En las expresiones regulares, se expresa de esta forma:
/(\d*)([a-z]*)/
grupo de captura()
Usando grupos de captura, podemos capturar personajes clave.
Por ejemplo
var group = '123456789hahaha'.match(/(\d*)([a-z]*)/)
El grupo 1 se utiliza para hacer coincidir cualquier número de números y el grupo 2 se utiliza para hacer coincidir cualquier número de letras minúsculas.
Luego match
podemos obtener los resultados coincidentes de estos dos grupos en el resultado de retorno del método, group[1]
sí "123456789"
, group[2]
sí "hahaha"
.
También podemos obtener el resultado del partido del grupo anterior en RegExp
el atributo estático . Sí Sí . _ Pero no es estándar, aunque muchos navegadores lo han implementado, trate de no usarlo en un entorno de producción.$1~$9
9
RegExp.$1
"123456789"
RegExp.$2
"hahaha"
RegExp.$1~$9
La aplicación de este tipo de grupo de captura es similar al replace
método de cadena, pero al llamar replace
al método, debemos referirnos al grupo a través $1
de $2
este formulario.$n
"123456789hahaha".replace(/(\d*)([a-z]*)/, "$1") // "123456789"
Usando $1
, podemos reemplazar la cadena de origen con la cadena que coincide con el grupo 1, es decir "123456789"
.
Grupo sin captura (?:)
Un grupo que no captura es un grupo que no genera una referencia, también está ()
entre paréntesis, pero el comienzo del paréntesis es ?:
, es decir, /(?:\d*)/
esta forma.
Echemos un vistazo al ejemplo anterior:
var group = '123456789hahaha'.match(/(?:\d*)([a-z]*)/)
Dado que los grupos que no capturan no generan referencias, lo group[1]
es "hahaha"
; de la misma manera, RegExp.$1
lo es "hahaha"
.
Al ver esto, no puedo evitar preguntarme, ya que no necesito hacer referencia al grupo que no captura, ¿cuál es el punto del grupo que no captura?
Después de pensarlo un rato, creo que el grupo sin captura tiene las siguientes ventajas y necesidades:
-
Un grupo que no captura es menos costoso en memoria que un grupo que captura porque no requiere que se genere una referencia.
-
La agrupación se realiza para facilitar la adición de cuantificadores. Aunque no podemos generar referencias, si no hay agrupación no es conveniente añadir cuantificadores a un grupo de caracteres.
'1a2b3c...'.match(/(?:\d[a-z]){2,3}(\.+)/)
Cita\núm
Las expresiones regulares pueden hacer referencia a grupos anteriores con referencias. De esta forma \1
, \2
se puede hacer referencia a la subexpresión anterior.
Por ejemplo, si quiero hacer coincidir una cadena, debe cumplir las siguientes reglas:
La cadena comienza y termina con comillas simples o dobles, y el contenido del medio puede ser números o palabras.
Entonces lo que quiero asegurar es que el principio y el final sean comillas simples o dobles, por lo que mi patrón se puede escribir como:
var pattern = /^(["'])[a-z\d]*\1$/ pattern.test("'perfect123'") // true
pattern.test('"1perfect2"') // true
aserción de ancho cero
Para ser honesto, cuando miré por primera vez el concepto y la explicación de las afirmaciones de ancho cero, realmente no entendí de qué estaba hablando.
- Aserción de anticipación de ancho cero (?=)
- Aserción de anticipación negativa de ancho cero (?!)
- Aserción retrospectiva positiva de ancho cero (?<=)
- Afirmación inversa negativa de ancho cero (?<!)
Más tarde, separé el vocabulario y agregué mi propio entendimiento, y gradualmente lo entendí un poco.
- Ancho cero: ancho cero, la afirmación se utiliza como condición necesaria para la coincidencia, pero no se refleja en el resultado de la coincidencia.
- Positivo: positivo, los caracteres de la afirmación deben coincidir.
- Negativo: negativo, los caracteres de la afirmación no pueden coincidir.
- Previsión: la previsión debe cumplir las condiciones del frente, las condiciones están en el frente y el frente es igual al lado derecho.
- Fila trasera: mirando hacia atrás, debe cumplir con las condiciones de la parte trasera, la condición es en la parte trasera, la parte trasera es igual al lado izquierdo.
Aserción de anticipación de ancho cero (?=)
El carácter especificado debe existir a la derecha del objetivo de la restricción.
/123(?=a)/.test('123a') // true
El ejemplo anterior restringe 123
la presencia del lado derecho a
.
Aserción de anticipación negativa de ancho cero (?!)
El carácter especificado no puede existir en el lado derecho del objetivo de restricción.
/123(?!a)/.test('123a') // false
El ejemplo anterior restringe que 123
no puede haber ninguno en el lado derecho a
; de lo contrario, el resultado es false
.
Aserción retrospectiva positiva de ancho cero (?<=)
El carácter especificado debe existir a la izquierda del objetivo de la restricción.
/(?<=a)123/.test('a123') // true
El ejemplo anterior restringe 123
la presencia del lado izquierdo a
.
Solo ES2018 admite afirmaciones de línea detrás de ancho cero
Afirmación inversa negativa de ancho cero (?<!)
El carácter especificado no puede existir en el lado izquierdo del objetivo de restricción.
/(?<!a)123/.test('a123') // false
El ejemplo anterior restringe que 123
no puede haber ninguno en el lado izquierdo a
; de lo contrario, el resultado esfalse
Nota: Esta función solo es compatible con ES2018.
ExpReg
Cuando se trata de expresiones regulares, tenemos que mencionar RegExp
los objetos. A continuación, aprenderemos sobre los objetos desde varios aspectos, como métodos prototipo, propiedades estáticas y propiedades de instancia RegExp
.
método prototipo
RegExp.prototipo.prueba
test()
Es nuestro método regular más utilizado. test()
El método realiza una recuperación para comprobar si la expresión regular coincide con la cadena especificada y devuelve un valor booleano true
o false
.
Si la expresión regular tiene establecido el indicador global g
, la ejecución test()
cambiará RegExp.lastIndex
el atributo utilizado para registrar el índice inicial del último carácter coincidente. Si el método se ejecuta continuamente test()
, las ejecuciones posteriores lastIndex
coincidirán con la cadena que comienza desde este punto. En este caso, si test()
el resultado no coincide, lastIndex
se restablecerá a 0
.
RegExp.prototipo.exec
exec()
En comparación con test()
obtener información de coincidencia más rica, el resultado es una matriz. El elemento 0 de la matriz es la cadena coincidente y los elementos del 1 al n son los ()
resultados capturados mediante la agrupación entre paréntesis.
La matriz de resultados es una matriz y la matriz también son datos de tipo objeto, por lo que la matriz de resultados también tiene dos atributos: index
yinput
index
Representa el valor de índice basado en 0 del carácter coincidente en la cadena original.input
luego representa la cadena original
De acuerdo con test()
la expresión regular, si se establece el indicador , se actualizará g
en cada ejecución .exec()
lastIndex
propiedades estáticas
Las propiedades estáticas no pertenecen a ninguna instancia y se debe acceder a ellas a través del nombre de la clase.
Exp.reg.$1-$9
Se utiliza para obtener el resultado coincidente del grupo: RegExp.$1
se obtiene el resultado coincidente del primer grupo RegExp.$9
y se obtiene el resultado coincidente del noveno grupo.
Propiedades de instancia
último índice
lastIndex
, entendido semánticamente, es el índice inicial del último carácter coincidente. Cabe señalar que esto sólo es efectivo si g
la bandera está configurada lastIndex
.
Cuando aún no hay ninguna coincidencia, lastIndex
naturalmente 0
significa que la coincidencia comienza desde la enésima 0
cadena.
lastIndex
se actualizará como exec()
el ytest()
var reg = /\d/g reg.lastIndex // 0
reg.test('123456') reg.lastIndex // 1
reg.exec('123456') reg.lastIndex // 2
lastIndex
Se puede modificar manualmente, lo que significa que tienes control gratuito sobre los detalles del partido.
banderas
flags
La propiedad devuelve una cadena que representa qué indicadores están habilitados para esta instancia de expresión regular.
var reg = /\d/ig reg.flags; // "gi"
global
global
Es un valor booleano que indica si la expresión regular utiliza g
banderas.
ignorar caso
ignoreCase
Es un valor booleano que indica si la expresión regular utiliza i
banderas.
multilínea
multiline
Es un valor booleano que indica si la expresión regular utiliza m
banderas.
fuente
source
, que significa fuente, es una representación de cadena de una expresión regular y no incluye barras a ambos lados del literal regular ni ningún carácter de bandera.
Métodos de cadena que implican regularidad.
Cadena.prototipo.búsqueda
search()
El método realiza una coincidencia en un objeto de cadena utilizando una expresión regular y devuelve un index
índice que representa la primera coincidencia de la expresión regular en la cadena. Si no se encuentra ninguna coincidencia, devuelva -1
.
search()
El parámetro del método debe ser una expresión regular; de lo contrario, se convertirá new RegExp()
silenciosamente en un objeto de expresión regular.
"123abc".search(/[a-z]/); // 3
Cadena.prototipo.coincidencia
El método de cadena se utiliza para recuperar cadenas y es similar al método match
de expresión regular . También es necesario que los parámetros del método sean expresiones regulares. El método devuelve una matriz.exec
match
match
exec()
La diferencia entre y es que si la match
expresión regular pasada por el método está marcada g
, se devolverán todos los resultados que coincidan con la expresión regular completa, pero no se devolverá el grupo de captura.
"123abc456".match(/([a-z])/g);
// 返回["a", "b", "c"]
var reg = /([a-z])/g; reg.exec('123abc456');
// 返回数组
["a", "a", index: 3, input: "123abc456", groups: undefined] reg.exec('123abc456');
// 返回数组
["b", "b", index: 4, input: "123abc456", groups: undefined] reg.exec('123abc456');
// 返回数组
["c", "c", index: 5, input: "123abc456", groups: undefined]
Si match()
la expresión regular pasada por el método no tiene un indicador g
, el comportamiento exec()
es consistente con el método y solo se devolverá el primer resultado coincidente y el resultado capturado agrupado.
Si hay una agrupación entre paréntesis en la expresión en este momento, match()
los resultados de estas coincidencias de agrupación también se pueden obtener en la matriz de resultados, lo que también se menciona en el grupo de captura.
"123abc456".match(/([a-z])/); // 返回["a", "a", index: 3, input: "123abc456", groups: undefined] RegExp.$1; // "a"
Cadena.prototipo.reemplazar
replace()
Es un método de reemplazo de cadenas, no requiere que el primer parámetro sea una expresión regular. Si el primer parámetro es una expresión regular y contiene agrupación, en el replace()
segundo parámetro, se puede hacer referencia al resultado de la coincidencia de agrupación "$1"
de "$2"
esta forma.
"123456789hahaha".replace(/(\d*)([a-z]*)/, "$1") // "123456789"
Cadena.prototipo.split
split()
El método es el método de división de cadenas, que también es un método de uso común, pero muchas personas no saben que puede aceptar expresiones regulares como parámetros.
Supongamos que obtenemos una cadena tan irregular "1,2, 3 ,4, 5"
y luego necesitamos dividir la cadena para obtener una matriz de números puros. split(",")
No es posible usarlo directamente, pero se puede hacer usando expresiones regulares como condiciones de división.
var str = "1,2, 3 ,4, 5"; str.split(/\s*,\s*/); // 返回 ["1", "2", "3", "4", "5"]
por fin
Las expresiones regulares son un punto de conocimiento muy importante pero que fácilmente se pasa por alto, y también es un punto de prueba frecuente en las entrevistas, por lo que se le debe prestar suficiente atención. Después de resolver los puntos de conocimiento anteriores, creo que puedo estar seguro y tranquilo en el combate real posterior.
Viene con 250 conjuntos de códigos fuente de proyectos seleccionados.
Captura de pantalla del código fuente
Adquisición del código fuente: siga la cuenta pública "Coder Park" y responda [código fuente] para obtener el conjunto completo de enlaces de descarga del código fuente.