7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. Swift

Swift y Expresiones Regulares: Swift

Scroll to top
Read Time: 10 mins
This post is part of a series called Swift and Regular Expressions: Syntax.
Swift and Regular Expressions: Syntax

Spanish (Español) translation by Elías Nicolás (you can also view the original English article)

En el primer tutorial de esta serie, exploramos los conceptos básicos de las expresiones regulares, incluyendo la sintaxis para escribir expresiones regulares. En este tutorial, aplicamos lo que hemos aprendido hasta ahora para aprovechar expresiones regulares en Swift.

1. Expresiones Regulares en Swift

Abra Xcode, cree un nuevo Playground, póngale RegExTut y establezca Platform en OS X. La elección de la plataforma, iOS u OS X, no hace ninguna diferencia con respecto a la API que vamos a utilizar.

Create a PlaygroundCreate a PlaygroundCreate a Playground

Antes de comenzar, hay otra cosa que usted necesita saber. En Swift, debe usar dos barras diagonales inversas, \\, para cada barra invertida que utilice en una expresión regular. La razón tiene que ver con Swift que tiene literales de cadena de estilo C. La barra invertida se procesa como un escape de caracteres, además de su papel en la interpolación de cadenas en Swift. En otras palabras, es necesario escapar del carácter de escape. Si eso suena extraño, no te preocupes por eso. Sólo recuerde, para utilizar dos barras inversas en lugar de uno.

En el primer ejemplo, un poco artificial, nos imaginamos que estamos buscando a través de una cadena buscando un tipo muy específico de dirección de correo electrónico. La dirección de correo electrónico cumple los siguientes criterios:

  • La primera letra es la primera letra del nombre de la persona
  • Seguido por un punto
  • Seguido del apellido de la persona
  • Seguido por el símbolo @
  • Seguido de un nombre, que representa una universidad en el Reino Unido
  • Seguido por .ac.uk, el dominio de las instituciones académicas en el Reino Unido

Agregue el siguiente código y revisemos este fragmento de código paso a paso.

Paso 1

Definimos un patrón. Observe las barras inversas doblemente escapadas. En la representación regular (normal), como la que se usa en el sitio web RegExr, esto sería ([a-z])\.([a-z]{2,})@([a-z]+)\.ac\.uk. También tenga en cuenta el uso de paréntesis. Están siendo utilizados para definir grupos de captura con los cuales podemos extraer las subcadenas que coincidan con esa parte de la expresión regular.

Usted debe ser capaz de hacer que el primer grupo de captura captura la primera letra del nombre del usuario, el segundo su apellido y el tercero el nombre de la universidad. Observe también el uso de la barra invertida para escapar del carácter de período para representar su significado literal. Alternativamente, podríamos ponerlo en un conjunto de caracteres por sí mismo ([.]). En ese caso, no tendríamos que escaparlo.

Paso 2

Esta es la cadena en la que estamos buscando el patrón.

Paso 3

Creamos un objeto NSRegularExpression, pasando en el patrón sin opciones. En la lista de opciones, puede especificar constantes NSRegularExpressionOption, como:

  • CaseInsensitive: Esta opción especifica que la coincidencia no distingue entre mayúsculas y minúsculas.
  • IgnoreMetacharacters: Utilice esta opción si desea realizar una coincidencia literal, lo que significa que los metacaracteres no tienen un significado especial y coinciden como caracteres comunes.
  • AnchorMatchLines: Utilice esta opción si desea que las anclas ^ y $ coincidan con el inicio y el final de las líneas (separadas por saltos de línea) en una sola cadena, en lugar del comienzo y el final de toda la cadena.

Debido a que el inicializador está lanzando, usamos la palabra clave try. Si pasamos una expresión regular no válida, por ejemplo, se produce un error.

Paso 4

Buscamos coincidencias en la cadena de prueba invocando matchesInString(_:options:range:), pasando en un intervalo para indicar en qué parte de la cadena estamos interesados. Este método también acepta una lista de opciones. Para simplificar, no pasamos ninguna opción en este ejemplo. Hablaré de opciones en el siguiente ejemplo.

Las coincidencias se devuelven como una matriz de objetos NSTextCheckingResult. Podemos extraer las coincidencias, incluyendo los grupos de captura, de la siguiente manera:

El fragmento anterior itera a través de cada objeto NSTextCheckingResult de la matriz. La propiedad numberOfRanges para cada coincidencia en el ejemplo tiene un valor de 4, una para la subcadena completa correspondiente a una dirección de correo electrónico (por ejemplo, a.khan@surrey.ac.uk) y las tres restantes corresponden a los tres grupos de captura Dentro del fósforo ("a", "khan", y "surrey" respectivamente).

El método rangeAtIndex(_:) devuelve el rango de las subcadenas en la cadena para poder extraerlas. Tenga en cuenta que, en lugar de utilizar rangeAtIndex(0), también podría utilizar la propiedad range para toda la coincidencia.

Haga clic en el botón Show Result en el panel de resultados de la derecha. Esto nos muestra "Surrey", el valor de testStr.substringWithRange(r) para la última iteración del bucle. Haga clic con el botón secundario en el campo de resultados y seleccione Value History para mostrar un historial de valores.

Show Value HistoryShow Value HistoryShow Value History

Usted puede modificar el código anterior para hacer algo significativo con los partidos y / o los grupos de captura.

Hay una forma conveniente de realizar operaciones de búsqueda y sustitución, utilizando una cadena de plantilla que tiene una sintaxis especial para representar los grupos de captura. Siguiendo con el ejemplo, supongamos que queríamos reemplazar todas las direcciones de correo electrónico con una subcadena de la forma "apellido, inicial, universidad", podríamos hacer lo siguiente:

Observe la sintaxis $n de la plantilla, que actúa como marcador de posición para el texto del grupo de captura n. Tenga en cuenta que $0 representa la coincidencia entera.

2. Un ejemplo más avanzado

El método matchesInString(_:options:range:) es uno de varios métodos de conveniencia que dependen de enumerateMatchesInString(_:options:range:usingBlock, que es el método más flexible y general (y por lo tanto complicado) en la clase NSRegularExpression. Este método llama a un bloque después de cada coincidencia, lo que le permite realizar cualquier acción que desee.

Al pasar una o más reglas de concordancia, utilizando las constantes NSMatchingOptions, puede asegurarse de que el bloque se invoca en otras ocasiones. Para operaciones de larga duración, puede especificar que el bloque se invoca periódicamente y finalizar la operación en algún momento. Con la opción ReportCompletion, especifica que el bloque debe ser invocado al finalizar.

El bloque tiene un parámetro flags que informa cualquiera de estos estados para que pueda decidir qué acción tomar. Similar a algunos otros métodos de enumeración en el marco Foundation, el bloque también puede ser terminado a su discreción. Por ejemplo, si una coincidencia de ejecución larga no tiene éxito o si ha encontrado coincidencias suficientes para comenzar el procesamiento.

En este escenario, vamos a buscar a través de algún texto para cadenas que parecen fechas y comprobar si una determinada fecha está presente. Para mantener el ejemplo manejable, nos imaginamos que las cadenas de fecha tienen la siguiente estructura:

  • Un año con dos o cuatro dígitos (por ejemplo, 09 o 2009)
  • Sólo a partir del presente siglo (entre 2000 y 2099) por lo que 1982 sería rechazado y 16 se interpretaría automáticamente como 2016
  • Seguido de un separador
  • Seguido por un número entre 1 y 12 que representa el mes
  • Seguido de un separador
  • Concluyendo con un número entre 1 y 31 que representa el día

Los meses y las fechas de un solo dígito posiblemente podrían estar rellenados con un cero inicial. Los separadores válidos son un guión, un punto y una barra diagonal. Aparte de los requisitos anteriores, no estaremos verificando si una fecha es realmente válida. Por ejemplo, estamos bien con fechas como 2000-04-31 (abril tiene sólo 30 días) y 2009-02-29 (2009 no es un año bisiesto, lo que significa que febrero tiene sólo 28 días) que no son fechas reales .

Agregue el siguiente código y revisemos este fragmento de código paso a paso.

Paso 1

La fecha cuya existencia estamos comprobando va a estar en un formato estandarizado. Utilizamos una tupla nombrada. Sólo pasamos un número entero de dos dígitos al año, es decir, 16 significa 2016.

Paso 2

Nuestra tarea consiste en enumerar a través de coincidencias que parezcan fechas, extraer los componentes del año, mes y día de ellos y comprobar si coinciden con la fecha en la que pasamos. Crearemos una función para hacer todo esto por nosotros. La función devuelve true o false dependiendo de si se encontró o no la fecha.

Paso 3

El patrón de fecha tiene algunas características interesantes:

  • Obsérvese el fragmento (?:20)?. Si sustituimos este fragmento por (20)?, esperamos que reconozcas que esto significa que estamos bien con el "20" (representando el milenio) presente o no en el año. Los paréntesis son necesarios para agrupar, pero no nos importa formar un grupo de captura con este par de paréntesis y eso es para lo que esta el ?:.
  • Los posibles separadores dentro del conjunto de caracteres [-./] No necesitan ser escapados para representarse a su mismo literal. Puedes pensar en esto así. El guión, -, está en el inicio por lo que no puede representar un rango. Y no tiene sentido para el punto,., Para representar cualquier carácter dentro de un conjunto de caracteres ya que lo hace igualmente bien fuera.
  • Hacemos un uso intensivo de la barra vertical para la alteración para representar las varias posibilidades de dígito mes y fecha.

Paso 4

La variable booleana notFound será devuelta por la función, indicando si se encontró o no la fecha buscada.

Paso 5

Se está llamando enumerateMatchesInString(_:options:range:usingBlock:) . No estamos usando ninguna de las opciones y estamos pasando en toda la gama del texto que se está buscando.

Paso 6

El objeto de bloque, invocado después de cada coincidencia, tiene tres parámetros:

  • La coincidencia (un NSTextCheckingResult)
  • opciones que representan el estado actual del proceso de coincidencia (que estamos ignorando aquí)
  • Una variable booleana stop, que podemos establecer dentro del bloque para salir temprano

Utilizamos el booleano para salir del bloque si encontramos la fecha que buscamos ya que no necesitamos buscar más. El código que extrae los componentes de la fecha es bastante similar al ejemplo anterior.

Paso 7

Comprobamos si los componentes extraídos de la subcadena igualada son iguales a los componentes de la fecha deseada. Tenga en cuenta que forzamos un Int, que estamos seguros de que no fallará porque creamos los grupos de captura correspondientes para sólo coincidir con los dígitos.

Paso 8

Si se encuentra una coincidencia, fijamos notFound a true. Salimos del bloque estableciendo stop.memory en true. Lo hacemos porque stop es un puntero-a-un-booleano y la forma en que Swift se ocupa de la memoria "apuntada" es a través de la propiedad de memoria.

Observe que la subcadena "2015/10/10" en nuestro texto corresponde a PossibleDate(15, 10, 10), por lo que la función devuelve true en el primer caso. Sin embargo, ninguna cadena en el texto corresponde a PossibleDate(13, 1, 1), es decir, "2013-01-01" y la segunda llamada a la función devuelve false.

OutputOutputOutput

Conclusion

Hemos estudiado de forma lenta, pero razonablemente detallada, cómo funcionan las expresiones regulares, pero hay mucho más que aprender si estás interesado, como las aserciones lookahead y lookbehind, aplicar expresiones regulares a cadenas Unicode, además de mirar el Varias opciones que navegamos en la API de la Fundación.

Incluso si decides no ahondar más, espero que hayas recogido lo suficiente aquí para ser capaz de identificar situaciones en las que regexes podría ser útil, así como algunos consejos sobre cómo diseñar regexes para resolver sus problemas de búsqueda de patrones.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.