Encuentra el personaje extraño en un patrón

20

Entrada

La primera línea será una cierta cadena repetida cualquier cantidad de veces. Por ejemplo, podría ser abcabcabcabc, [];[];[];, etc. Puede ser cortada; por ejemplo: 1231231231. Encuentra siempre la cuerda más corta; por ejemplo, si la línea es 22222, entonces la cadena es 2, no 22o 22222o cualquier otra cosa. La cadena siempre se repetirá al menos 2 veces completas.

Todas las líneas posteriores serán ese patrón compensado por cualquier número. Por ejemplo, podría ser:

abcabcabc
cabcabcab
bcabcabca

(compensado por 1), o podría ser:

abcdefabcdefabcdefabc
cdefabcdefabcdefabcde
efabcdefabcdefabcdefa

(compensado por 4).

Uno de los caracteres en la entrada estará equivocado. (Se garantiza que no estará en la primera línea). Por ejemplo, en esta entrada:

a=1a=1a=1
=1a=1a=1a
1a=11=1a=
a=1a=1a=1
=1a=1a=1a

el 1de la línea 3 es el extraño.

Salida

Debe generar las coordenadas (basadas en cero, comenzando desde la parte superior izquierda) de la impar. Por ejemplo, en la entrada anterior, la salida correspondiente es 4,2. También puede generar 4 2, o "4""2", o incluso[[4],[2]] , o cualquier otro formato, siempre que pueda saber cuál se supone que es la salida.

Casos de prueba

Entrada:

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

Salida: 16,2

Entrada:

][[][][[][][[][][[][][[
[][][[][][[][][[][][[][
[][[][][[][][[][][[][][
[[][][[]]][[][][[][][[]

Salida: 8,3

Entrada:

...
. .
...

Salida: 1,1

Entrada:

ababa
babab
ababb
babab

Salida: 4,2

¡Vamos!

Pomo de la puerta
fuente
¿Qué caracteres pueden estar contenidos en la cadena? ASCII imprimible? ASCII? Unicode?
Dennis
@Dennis Solo ASCII imprimible (que básicamente se puede suponer para cualquier desafío que implique cadenas; de lo contrario, tendríamos que especificar eso para casi todos los desafíos: P)
Pomo de la puerta
Supongo. Estoy pensando en un enfoque que requiera un carácter no utilizado, así que pensé en preguntar.
Dennis
¿Deberíamos verificar un caso como este: abc/cab/abc- y salida 0 2aquí?
user2846289
@VadimR No, ya que solo un personaje estará equivocado.
Pomo de la puerta

Respuestas:

7

Bash Perl, 231 229 218 178 164 166 138 106 74 bytes

/^(((.*).*)\2+)\3$/;$_.=$1x2;$.--,die$+[1]if/^(.*)(.)(.*)
.*\1(?!\2).\3/

La secuencia de comandos requiere el uso del -ninterruptor, que representa dos de los bytes.

La idea de agregar dos copias de todas las repeticiones completas del patrón ha sido tomada de la respuesta de MT0 .

A diferencia de todas las otras respuestas, este enfoque intenta extraer el patrón de la línea de entrada actual en cada iteración; fallará en la línea que contiene el carácter impar (y usará el patrón de la línea anterior). Esto se hace para incluir la extracción del patrón en el bucle, que logra guardar algunos bytes.

Versión sin golf

#!/usr/bin/perl -n

# The `-n' switch makes Perl execute the entire script once for each input line, just like
# wrapping `while(<>){…}' around the script would do.

/^(((.*).*)\2+)\3$/;

# This regular expression matches if `((.*).*)' - accessible via the backreference `\2' -
# is repeated at least once, followed by a single repetition of `\3" - zero or more of the
# leftmost characters of `\2' - followed by the end of line. This means `\1' will contain
# all full repetitions of the pattern. Even in the next loop, the contents of `\1' will be
# available in the variable `$1'.

$_.=$1x2;

# Append two copies of `$1' to the current line. For the line, containing the odd
# character, the regular expression will not have matched and the pattern of the previous
# line will get appended.
#
# Since the pattern is repeated at least two full times, the partial pattern repetition at
# the end of the previous line will be shorter than the string before it. This means that
# the entire line will the shorter than 1.5 times the full repetitions of the pattern, 
# making the two copies of the full repetitions of the pattern at least three times as 
# long as the input lines.

$.-- , die $+[1] if

# If the regular expression below matches, do the following:
#
#   1. Decrement the variable `$.', which contains the input line number.
#
#      This is done to obtain zero-based coordinates.
#
#   2. Print `$+[1]' - the position of the last character of the first subpattern of the
#      regular expression - plus some additional information to STDERR and exit.
#
#      Notably, `die' prints the (decremented) current line number.

/^(.*)(.)(.*)
.*\1(?!\2).\3/;

# `(.*)(.)(.*)', enclosed by `^' and a newline, divides the current input line into three
# parts, which will be accesible via the backreferences `\1' to `\3'. Note that `\2'
# contains a single character.
#
# `.*\1(?!\2).\3' matches the current input line, except for the single character between
# `\1' and `\3' which has to be different from that in `\2', at any position of the line
# containing the pattern repetitions. Since this line is at least thrice as long as
# `\1(?!\2).\3', it will be matched regardless of by how many characters the line has been
# rotated.

Ejemplo

Para el caso de prueba

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

la salida de la versión de golf es

16 at script.pl line 1, <> line 2.

lo que significa que el personaje impar tiene las coordenadas 16,2.

Estos abusos descarados aprovechan el formato de salida liberal.

Justo antes de salir, el contenido de algunas de las variables especiales de Perl son:

$_  = lfcodegolfcodegoff\ncodegolfcodegolfcodegolfcodegolf
$1  = lfcodegolfcodego
$2  = f
$3  = f

( $ncontiene la coincidencia del subpatrón accesible a través de la referencia inversa \n).

Dennis
fuente
Captura inteligente de la unidad de respuesta. Se puede optimizar en un byte:^((.*?)(.*?))(?=\1+\2$)
Heiko Oberdiek
Cambié al idioma que usan los niños populares. Probablemente se pueda jugar más golf; Este es mi primer guión de Perl en más de una década ...
Dennis
2
... y llegas más de una década tarde si crees que Perl es lo que usan los niños populares
ardnew
Esta respuesta no es obtener el amor que merece. me parece el ganador @Doorknob
ardnew 01 de
8

Perl, 212 191 181 168 bytes

$_=<>;/^(((.*?)(.*?))\2+)\3$/;$x=$1x4;while(<>){chop;$x=~/\Q$_\E/&&next;for$i(0..y///c-1){for$r(split//,$x){$b=$_;$b=~s/(.{$i})./$1$r/;$x=~/\Q$b\E/&&die$i,$",$.-1,$/}}}
  • Esta versión utiliza un truco optimizado para atrapar la unidad de respuesta, que se aprende en la respuesta de Dennis .
  • Optimización mediante el uso de la propiedad de que todas las líneas tienen la misma longitud.
  • El final de línea también es necesario para la última línea, de lo contrario, en chomplugar dechop debe usarse.
  • Optimizaciones de ardnew comentario .

Versión anterior, 212 bytes:

$_=<>;chop;/^(.+?)\1+(??{".{0,".(-1+length$1).'}'})$/;$;=$1;while(<>){$x=$;x length;chop;$x=~/\Q$_\E/&&next;for$i(0..-1+length$_){for$r(split//,$;){$b=$_;$b=~s/(.{$i})./$1$r/;$x=~/\Q$b\E/&&exit print$i,$",$.-1}}}

Versión sin golf:

$_ = <>;  # read first line
/^(((.*?)(.*?))\2+)\3$/;
# The repeat unit \2 consists of \3 and \4,
# and the start part \2 can be added at the end (as partial or even full unit).
$x = $1 x 4; # $x is long enough to cover each following line

# Old version:
# /^(.+?)\1+(??{ ".{0," . (-1 + length $1) . '}' })$/;
# $a = $1; # $a is the repeat unit.
# The unit is caught by a non-greedy pattern (.+?) that is
# repeated at least once: \1+
# The remaining characters must be less than the unit length.
# The unit length is known at run-time, therefore a "postponed"
# regular expression is used for the remainder.

# process the following lines until the error is found
while (<>) {
    # old version:
    # $x = $a x length;
    # $x contains the repeated string unit, by at least one unit longer
    # than the string in the current line
    chop; # remove line end of current line
    $x =~ /\Q$_\E/ && next;
          # go to next line, if current string is a substring of the repeated units;
          # \Q...\E prevents the interpretation of special characters
    # now each string position $x is checked, if it contains the wrong character:
    for $i (0 .. y///c - 1) {  # y///c yields the length of $_
        for $r (split //, $x) { #/ (old version uses $a)
            # replace the character at position $i with a
            # character from the repeat unit
            $b = $_;
            $b =~ s/(.{$i})./$1$r/;
            $x =~ /\Q$b\E/
               && die $i, $", $. - 1, $/;
               # $" sets a space and the newline is added by $/;
               # the newline prevents "die" from outputting line numbers
        }
    }
}
Heiko Oberdiek
fuente
Gran solución y comentarios, necesito aprender más
expresiones
1
el primero chopes innecesario, debe eliminarse. el final exit printse puede reemplazar con die(agregar ,$/para ocultar las cosas adicionales (si es necesario)). también length$_se puede reemplazar cony///c
ardnew
@ardnew: Muchas gracias, he eliminado el primero chop, porque $coincide antes de la nueva línea al final de la cadena. Ocultar las cosas adicionales a dietravés de la nueva línea agregada me parece necesario. También y///ces mucho más corto que length$_y un byte más corto que lengthsin lo innecesario $_.
Heiko Oberdiek
1
@ardnew: me había olvidado de la verbosidad de die . ¡Incluso incluye impresiones del número de línea! Lo usaré en mi próxima actualización.
Dennis
3

C, 187 bytes

Limitaciones

  • No use cadenas de entrada de más de 98 caracteres :)

Versión de golf

char s[99],z[99],*k,p,i,I,o,a;c(){for(i=0;k[i]==s[(i+o)%p];i++);return k[i];}main(){for(gets(k=s);c(p++););for(;!(o=o>p&&printf("%d,%d\n",I,a))&&gets(k=z);a++)while(o++<p&&c())I=I<i?i:I;}

Versión sin golf

char s[99],z[99],*k,p,i,I,o,a;

c()
{
    for(i=0
       ;k[i]==s[(i+o)%p]
       ;i++)
       ;
    return k[i];
}

main()
{
    for(gets(k=s);c(p++);)
         ;
    for(;!(o=o>p&&printf("%d,%d\n",I,a)) && gets(k=z);a++)
           while(o++ < p && c())
            I=I<i?i:I;
}
asr
fuente
2

Python, 303 292

r=raw_input
R=range
s=r()
l=len(s)
m=1
g=s[:[all((lambda x:x[1:]==x[:-1])(s[n::k])for n in R(k))for k in R(1,l)].index(True)+1]*l*2
while 1:
 t=r()
 z=[map(lambda p:p[0]==p[1],zip(t,g[n:l+n]))for n in R(l)]
 any(all(y)for y in z)or exit("%d,%d"%(max(map(lambda b:b.index(False),z)),m))
 m+=1

La entrada pasa por stdin. Lo explicaré si hay alguna demanda, pero no parece que vaya a ganar de todos modos.

Fraxtil
fuente
1

Perl, 157 154

Editar : -3 gracias a la sugerencia de ardnew.

<>=~/^(((.*?).*?)\2+)\3$/;$p=$2;$n=$+[1];while(<>){s/.{$n}/$&$&/;/(\Q$p\E)+/g;$s=$p;1while/./g*$s=~/\G\Q$&/g;print$n>--($m=pos)?$m:$m-$n,$",$.-1,$/if pos}

Me tomó algo de tiempo (dentro y fuera, por supuesto, no 5 días ;-)), y la idea sobre el algoritmo fue inicialmente difícil de alcanzar (aunque sentí que estaba allí), pero finalmente (y de repente) se hizo evidente.

Si la longitud de la cadena es múltiplo de la longitud del patrón, e incluso si la cadena no comienza con el comienzo del patrón, la cadena de concatenación producirá un patrón en lugar de la concatenación (imagine la repetición infinita de una palabra en la cinta circular, el lugar de la soldadura no es importante). Por lo tanto, la idea es recortar la línea a varias unidades de longitud y concatenar el original. El resultado, incluso para la cadena que contiene el carácter incorrecto, se garantiza que coincida con el patrón al menos una vez. A partir de ahí, es fácil encontrar la posición del personaje ofensivo.

La primera línea se toma prestada descaradamente de la respuesta de Heiko Oberdiek :-)

<>=~/^(((.*?).*?)\2+)\3$/;      # Read first line, find the repeating unit
$p=$2;                          # and length of whole number of units.
$n=$+[1];                       # Store as $p and $n.
while(<>){                      # Repeat for each line.
    s/.{$n}/$&$&/;              # Extract first $n chars and
                                # append original line to them.
    /(\Q$p\E)+/g;               # Match until failure (not necessarily from the
                                # beginning - doesn't matter).
    $s=$p;                      # This is just to reset global match position
                                # for $s (which is $p) - we could do without $s,
                                # $p.=''; but it's one char longer.
                                # From here, whole pattern doesn't match -
    1while/./g*$s=~/\G\Q$&/g;   # check by single char.
                                # Extract next char (if possible), match to 
                                # appropriate position in a pattern (position 
                                # maintained by \G assertion and g modifier).
                                # We either exhaust the string (then pos is 
                                # undefined and this was not the string we're
                                # looking for) or find offending char position.

    print$n>--($m=pos)?$m:$m-$n,$",$.-1,$/if pos
}
usuario2846289
fuente
1
Buen trabajo. creo que puede reemplazar /.{$n}/;$_=$&.$_;cons/.{$n}/$&$&/;
ardnew
1

JavaScript (ES6) - 147 133 136 Caracteres

s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Espera que la cadena que se probará esté en la variable sy envía el resultado a la consola.

var repetitionRE = /^(((.*).*)\2+)\3\n/;
                                        // Regular expression to find repeating sequence
                                        // without any trailing sub-string of the sequence.
var sequence = repetitionRE.exec(s)[1]; // Find the sequence string.
s.split('\n')                           // Split the input into an array.
 .map(
   ( row, index ) =>                    // Anonymous function using ES6 arrow syntax
   {
     var testStr = row + '᛫'+ sequence + sequence;
                                        // Concatenate the current row, a character which won't
                                        // appear in the input and two copies of the repetitions
                                        // of the sequence from the first line.
     var match = /^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(testStr);
                                        // Left of the ᛫ finds sub-matches for a single
                                        // character and the sub-strings before and after.
                                        // Right of the ᛫ looks for any number of characters
                                        // then the before and after sub-matches with a
                                        // different character between.
      if ( match )
       console.log( match[1].length, index );
                                        // Output the index of the non-matching character
                                        // and the row.
   }         
 );

Caso de prueba 1

s="codegolfcodegolfco\negolfcodegolfcodeg\nlfcodegolfcodegoff\nodegolfcodegolfcod\ngolfcodegolfcodego\nfcodegolfcodegolfc"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Salidas

16 2

Caso de prueba 2

s="][[][][[][][[][][[][][[\n[][][[][][[][][[][][[][\n[][[][][[][][[][][[][][\n[[][][[]]][[][][[][][[]"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Salidas

8 3

Caso de prueba 3

s="...\n. .\n..."
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Salidas

1 1

Caso de prueba 4

s="ababa\nbabab\nababb\nbabab"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Salidas

4 2

Caso de prueba 5

s="xyxy\nyyxy"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Salidas

0 1

Caso de prueba 6

s="ababaababa\nababaaaaba"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Salidas

6 1
MT0
fuente
Por desgracia, este enfoque falla si, por ejemplo, s="xyxy\nyyxy". Para la segunda línea, match[4]será yy; Debería ser justo y.
Dennis
Reelaborado y acortado por 14 caracteres.
MT0
¡Muy agradable! Había intentado la misma segunda expresión regular en algún momento, pero agregué el patrón mínimo dos veces en lugar del máximo (y, por lo tanto, fallé miserablemente). Un problema menor: la primera expresión regular informará sobre ababel patrón de ababaababa; Necesitas usar ^…$.
Dennis
/^…\n/funciona o/^…$/m
MT0
1
Es posible que no necesite el inicio ^(al menos no lo necesita para ninguno de los 6 casos de prueba que he enumerado, pero probablemente haya un contraejemplo donde lo haga, así que lo dejé).
MT0