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 btodo sería válido, pero
foo bbno sería
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])+$Detalles RegEx:
^ : Iniciofoo : 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$ : FinComo 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] .
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 cDemostració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))?)?$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 FalseO 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 ) )