Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

224
Vistas
python regex donde un conjunto de opciones puede ocurrir como máximo una vez en una lista, en cualquier orden

Me pregunto si hay alguna forma en python o perl para crear una expresión regular en la que pueda definir un conjunto de opciones que pueden aparecer como máximo una vez en cualquier orden. Entonces, por ejemplo, me gustaría un derivado de foo(?: [abc])* , donde a , b , c solo podrían aparecer una vez. Entonces:

 foo abc foo bca foo ab foo b

todo sería válido, pero

 foo bb

no sería

over 4 years ago · Santiago Trujillo
8 Respuestas
Responde la pregunta

0

No hay mucho que agregar a las respuestas anteriores, excepto que aquí hay una expresión regular que no usa referencias anteriores o posteriores. En su lugar, utiliza 3 aserciones anticipadas negativas separadas para garantizar que la entrada no contenga 2 apariciones de a o b o c . La expresión regular también permite usos liberales de espacios.

 ^foo(?![^a]*a[^a]*a)(?![^b]*b[^b]*b)(?![^c]*c[^c]*c)( +[abc])* *$

Ver demostración de expresión regular

  1. ^ - Coincide con el inicio de la cadena
  2. (?![^a]*a[^a]*a) - Afirmación anticipada negativa de que lo que sigue no contiene dos ocurrencias de a
  3. (?![^b]*b[^b]*b) - Afirmación anticipada negativa de que lo que sigue no contiene dos ocurrencias de b
  4. (?![^c]*c[^c]*c) - Afirmación anticipada negativa de que lo que sigue no contiene dos ocurrencias de c
  5. ( +[abc])* - Coincide con 0 o más apariciones de: 1 o más espacios seguidos de a o b o c
  6. * - Coincide con 0 o más ocurrencias del espacio 7 $ - Coincide con el final de la cadena

La expresión regular parece "torpe", pero es muy sencilla. Con la entrada foo abc , la coincidencia exitosa se realiza en 35 pasos y con la entrada foo bb , la coincidencia fallida se realiza en 13 pasos. Thich se compara favorablemente con las otras respuestas.

over 4 years ago · Santiago Trujillo Denunciar

0

Puede usar esta expresión regular con un grupo de captura y una anticipación negativa:

Para Perl , puede usar esta variante con referencia directa :

 ^foo((?!.*\1) [abc])+$

Demostración RegEx

Detalles RegEx:

  • ^ : Inicio
  • foo : Partido foo
  • ( : Iniciar un grupo de captura #1
    • (?!.*\1) : Anticipación negativa para afirmar que no coincidimos con lo que tenemos en el grupo de captura #1 en ninguna parte de la entrada
    • [abc] : coincide con un espacio seguido de a o b o c
  • )+ : Fin del grupo de captura #1. Repite este grupo 1+ veces
  • $ : Fin

Como se mencionó anteriormente, esta expresión regular está utilizando una función llamada referencia directa que es una referencia inversa a un grupo que aparece más adelante en el patrón de expresión regular . JGsoft, .NET, Java, Perl, PCRE, PHP, Delphi y Ruby permiten referencias directas pero Python no.


Aquí hay una solución alternativa de la misma expresión regular para Python que no usa referencias directas:

 ^foo(?!.* ([abc]).*\1)(?: [abc])+$

Aquí usamos una búsqueda anticipada negativa antes del grupo repetido para verificar y fallar la coincidencia si hay alguna repetición de subcadenas permitidas, es decir [abc] .

Demostración RegEx 2

over 4 years ago · Santiago Trujillo Denunciar

0

Puedes hacerlo usando referencias a grupos capturados previamente.

 foo(?: ([abc]))?(?: (?!\1)([abc]))?(?: (?!\1|\2)([abc]))?$

Esto se vuelve bastante largo con muchas opciones. Tal expresión regular se puede generar dinámicamente, si es necesario.

 def match_sequence_without_repeats(options, seperator): def prevent_previous(n): if n == 0: return "" groups = "".join(rf"\{i}" for i in range(1, n + 1)) return f"(?!{groups})" return "".join( f"(?:{seperator}{prevent_previous(i)}([{options}]))?" for i in range(len(options)) ) print(f"foo{match_sequence_without_repeats('abc', ' ')}$")
over 4 years ago · Santiago Trujillo Denunciar

0

Puede afirmar que no hay coincidencia para una segunda coincidencia para un espacio y una letra a la derecha:

 foo(?!(?: [abc])*( [abc])(?: [abc])*\1)(?: [abc])*
  • foo Match literalmente
  • (?! Anticipación negativa
    • (?: [abc])* Combina repeticiones opcionales de un espacio y ab o c
    • ( [abc]) Grupo de captura, se usa para comparar con una referencia inversa para el mismo
    • (?: [abc])* Haga coincidir de nuevo un espacio y ab o c
    • \1 Referencia inversa al grupo 1
  • ) Anticipación cercana
  • (?: [abc])* Combina repeticiones opcionales o un espacio y ab o c

Demostración de expresiones regulares

Si no desea hacer coincidir solo foo, puede cambiar el cuantificador a 1 o más (?: [abc])+


Una variante en perl que reutiliza el primer subpatrón usando (?1) que se refiere al grupo de captura ([abc])

 ^foo ([abc])(?: (?!\1)((?1))(?: (?!\1|\2)(?1))?)?$

Demostración de expresiones regulares

over 4 years ago · Santiago Trujillo Denunciar

0

Si el orden de las cadenas no importa y desea asegurarse de que cada cadena se presente solo una vez, puede convertir la lista en un conjunto en Python:

 my_lst = ['a', 'a', 'b', 'c'] my_set = set(lst) print(my_set) # {'a', 'c', 'b'}
over 4 years ago · Santiago Trujillo Denunciar

0

He asumido que los elementos de la cadena pueden estar en cualquier orden y aparecer cualquier número de veces. Por ejemplo, 'a foo' debe coincidir y 'a foo b foo' no.

Puede hacerlo con una serie de alternancias empleando búsquedas anticipadas, una para cada subcadena de interés, pero se convierte en un desayuno de perros cuando hay muchas cadenas a considerar. Supongamos que desea hacer coincidir cero o un "foo" y/o cero o un "a" . Podrías usar la siguiente expresión regular:

 ^(?:(?!.*\bfoo\b)|(?=(?:(?!\bfoo\b).)*\bfoo\b(?!(.*\bfoo\b))))(?:(?!.*\ba\b)|(?=(?:(?!\ba\b).)*\ba\b(?!(.*\ba\b))))

¡Arranca tu motor!

Esto coincide, por ejemplo, 'foofoo' , 'aa' y afooa . Si no van a coincidir, elimine la palabra saltos ( \b ).

Tenga en cuenta que esta expresión comienza afirmando el inicio de la cadena ( ^ ) seguido de dos anticipaciones positivas, una para 'foo' y otra para 'a' . Para verificar también, digamos, 'c' uno agregaría

 (?:(?!.*\bc\b)|(?=(?:(?!\bc\b).)*\bc\b(?!(.*\bc\b))))

que es lo mismo que

 (?:(?!.*\ba\b)|(?=(?:(?!\ba\b).)*\ba\b(?!(.*\ba\b))))

con \ba\b cambiado a \bc\b .

Sería bueno poder usar referencias anteriores, pero no veo cómo se podría hacer eso.

Al pasar el cursor sobre la expresión regular en el enlace, se proporciona una explicación para cada elemento de la expresión. (Si esto no está claro, me estoy refiriendo al cursor).

Tenga en cuenta que

 (?!\bfoo\b).

coincide con un carácter siempre que no comience con la palabra 'foo' . Por lo tanto

 (?:(?!\bfoo\b).)*

coincide con una subcadena que no contiene 'foo' y no termina con 'f' seguida de 'oo' .

¿Defendería este enfoque en la práctica, en lugar de utilizar métodos de cadenas simples? Déjame reflexionar sobre eso.

over 4 years ago · Santiago Trujillo Denunciar

0

Aquí hay una versión modificada de la respuesta de anubhava , usando una referencia inversa (que funciona en Python y es más fácil de entender al menos para mí) en lugar de una referencia directa.

Haga coincidir usando [abc] dentro de un grupo de captura, luego verifique que el texto coincidente con el grupo de captura no vuelva a aparecer en ningún lugar después de él:

 ^foo(?:( [abc])(?!.*\1))+$

demostración de expresiones regulares

  • ^ : Inicio
  • foo : Partido foo
  • (?: : Iniciar grupo sin captura (?:( [abc])(?!.*\1))
    • ( [abc]) : Capturando el Grupo 1, haciendo coincidir un espacio seguido de a , b o c
    • (?!.*\1) : Búsqueda anticipada negativa, que no logra la coincidencia si el texto coincidente con el primer grupo de captura aparece después de cero o más caracteres coincidentes con .
  • )+ : finaliza el grupo que no captura y emparejalo 1 o más veces
  • $ : Fin
over 4 years ago · Santiago Trujillo Denunciar

0

Si no tiene que ser una expresión regular:

 import collections # python >=3.10 def is_a_match(sentence): words = sentence.split() return ( (len(words) > 0) and (words[0] == 'foo') and (collections.Counter(words) <= collections.Counter(['foo', 'a', 'b', 'c'])) ) # python <3.10 def is_a_match(sentence): words = sentence.split() return ( (len(words) > 0) and (words[0] == 'foo') and not (collections.Counter(words) - collections.Counter(['foo', 'a', 'b', 'c'])) ) # TESTING #foo abc True #foo bca True #foo ab True #foo b True #foo bb False

O con un conjunto y el operador morsa:

 def is_a_match(sentence): words = sentence.split() return ( (len(words) > 0) and (words[0] == 'foo') and ( (s := set(words[1:])) <= set(['a', 'b', 'c']) and len(s) == len(words) - 1 ) )
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda