Retina , 61 55 bytes
^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$
Dado que esta es solo una expresión regular, Retina se ejecutará en modo Match e informará el número de coincidencias que encontró, que será 1
para secuencias válidas y de 0
otro modo. Esto no es competitivo en comparación con los idiomas de golf, pero estoy bastante contento con eso, ya que comencé con un monstruo de 260 bytes.
Explicación
^((.)(?<!\2.+))*
Este bit consume un prefijo de letras únicas de longitud variable, es decir, coincide con el fragmento inicial potencialmente incompleto. El aspecto posterior asegura que cualquier carácter que coincida en este bit no haya aparecido en la cadena antes.
Ahora, para el resto de la entrada, queremos unir fragmentos de 7 sin repetir caracteres. Podríamos igualar un trozo como este:
(.)(?!.{0,5}\1)(.)(?!.{0,4}\2)(.)(?!.{0,3}\3)...(.)(?!.?\5).
Es decir, hacemos coincidir un personaje que no aparece para otros 6 caracteres, luego uno que no aparece para otros 5 caracteres y así sucesivamente. Pero esto requiere una repetición de código bastante horrible, y tendríamos que hacer coincidir un fragmento final (potencialmente incompleto) por separado.
Equilibrio de grupos al rescate! Una forma diferente de combinar
(.)(?!.{0,5}\1)
es empujar 5 partidos vacíos en una pila de captura e intentar vaciarla:
(){5}(.)(?!(?<-1>.)*\2)
El *
permite un mínimo de cero repeticiones, al igual que {0,5}
, y porque nos hemos llevado cinco capturas, no será capaz de hacer estallar más de 5 veces tampoco. Esto es más largo para una sola instancia de este patrón, pero es mucho más reutilizable. Dado que estamos haciendo estallar en una búsqueda anticipada negativa , esto no afecta la pila real una vez que la búsqueda anticipada se ha completado. Entonces, después de la búsqueda anticipada, todavía tenemos 5 elementos en la pila, sin importar lo que sucedió dentro. Además, simplemente podemos extraer un elemento de la pila antes de cada búsqueda anticipada, y ejecutar el código en un bucle, para disminuir automáticamente el ancho de búsqueda anticipada de 5 a 0. De modo que ese bit realmente largo puede acortarse a
(){7}((?<-1>)(.)(?!(?<-1>.)*\1\3))*
(Puede notar dos diferencias: estamos presionando 7 en lugar de 5. Una captura adicional es porque hacemos estallar antes de cada iteración, no después de ella. La otra es realmente necesaria para que podamos hacer estallar desde la pila 7 veces (ya que queremos para que el ciclo se ejecute 7 veces), podemos corregir ese error fuera de uno dentro de la búsqueda anticipada asegurándonos de \1
que todavía queda al menos un elemento en la pila).
La belleza de esto es que también puede coincidir con el fragmento incompleto final, porque nunca lo exigimos que se repita 7 veces (ese es el máximo necesario, porque no podemos saltar de la pila con más frecuencia que eso). Entonces, todo lo que tenemos que hacer es envolver esto en otro bucle y asegurarnos de que hemos llegado al final de la cadena para obtener
^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$