Trouvez le caractère étrange dans un motif

20

Contribution

La première ligne sera une certaine chaîne répétée autant de fois. Par exemple, il pourrait être abcabcabcabc, [];[];[];etc. Il peut être coupé; par exemple: 1231231231. Trouvez toujours la chaîne la plus courte; par exemple, si la ligne est 22222, la chaîne est 2, pas 22ou 22222ou quoi que ce soit d' autre. La chaîne sera toujours répétée au moins 2 fois.

Toutes les lignes suivantes seront ce motif compensé par un nombre quelconque. Par exemple, cela pourrait être:

abcabcabc
cabcabcab
bcabcabca

(compensé par 1), ou ce pourrait être:

abcdefabcdefabcdefabc
cdefabcdefabcdefabcde
efabcdefabcdefabcdefa

(compensé par 4).

L'un des caractères de l'entrée sera erroné. (Il est garanti de ne pas être sur la première ligne.) Par exemple, dans cette entrée:

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

la 1ligne 3 est l'intrus.

Production

Vous devez sortir les coordonnées (de base zéro, en partant du coin supérieur gauche) de l'intrus. Par exemple, dans l'entrée ci-dessus, la sortie correspondante est 4,2. Vous pouvez également sortir 4 2, ou "4""2", ou même [[4],[2]], ou tout autre format, tant que vous pouvez dire ce que la sortie est censée être.

Cas de test

Contribution:

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

Production: 16,2

Contribution:

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

Production: 8,3

Contribution:

...
. .
...

Production: 1,1

Contribution:

ababa
babab
ababb
babab

Production: 4,2

Aller!

Poignée de porte
la source
Quels caractères peuvent être contenus dans la chaîne? ASCII imprimable? ASCII? Unicode?
Dennis
@Dennis ASCII imprimable (qui peut être supposé pour tout défi impliquant des chaînes; sinon, nous devrons le spécifier pour presque tous les défis: P)
Poignée de porte
Je l'ai deviné. Je pense à une approche qui nécessiterait un caractère inutilisé, alors j'ai pensé demander.
Dennis
Faut-il vérifier le cas comme ceci: abc/cab/abc- et sortir 0 2ici?
user2846289
@VadimR Non, car un seul caractère aura tort.
Poignée de porte

Réponses:

7

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

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

Le script nécessite l'utilisation du -ncommutateur, qui représente deux des octets.

L'idée d'ajouter deux copies de toutes les répétitions complètes du motif a été tirée de la réponse de MT0 .

Contrairement à toutes les autres réponses, cette approche tente d'extraire le modèle de la ligne d'entrée actuelle à chaque itération; il échouera sur la ligne contenant le caractère impair (et utilisera le modèle de la ligne précédente à la place). Cela est fait pour inclure l'extraction du modèle dans la boucle, qui parvient à économiser quelques octets.

Version non golfée

#!/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.

Exemple

Pour le cas de test

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

la sortie de la version golfée est

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

ce qui signifie que le caractère impair a les coordonnées 16,2.

Cet abus flagrant profite du format de sortie libéral.

Juste avant de quitter, le contenu de certaines variables spéciales de Perl est:

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

( $ncontient la correspondance du sous-modèle accessible via la référence arrière \n.)

Dennis
la source
Capture intelligente de l'unité de réponse. Il peut être optimisé d'un octet:^((.*?)(.*?))(?=\1+\2$)
Heiko Oberdiek
Je suis passé à la langue que les enfants populaires utilisent. Peut probablement être creusé plus loin; c'est mon premier script Perl en plus d'une décennie ...
Dennis
2
... et vous avez plus d'une décennie de retard si vous pensez que perl est ce que les enfants populaires utilisent
ardnew
cette réponse n'obtient pas l'amour qu'elle mérite. me ressemble comme le gagnant @Doorknob
ardnew
8

Perl, 212 191 181 181 168 octets

$_=<>;/^(((.*?)(.*?))\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,$/}}}
  • Cette version utilise une astuce optimisée pour attraper l'unité de réponse, apprise dans la réponse de Dennis .
  • Optimisation en utilisant la propriété que toutes les lignes ont des longueurs égales.
  • La fin de ligne est également nécessaire pour la dernière ligne, sinon chompau lieu de chopdevrait être utilisé.
  • Ajout des optimisations du commentaire d'ardnew .

Ancienne version, 212 octets:

$_=<>;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}}}

Version non golfée:

$_ = <>;  # 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
la source
Excellente solution et commentaires, j'ai besoin d'en savoir plus sur l'expression
régulière
1
le premier chopest inutile - devrait être supprimé. la finale exit printpeut être remplacée par die(ajouter ,$/pour masquer les éléments supplémentaires (si nécessaire)). length$_peut également être remplacé pary///c
ardnew
@ardnew: Merci beaucoup, j'ai supprimé le premier chop, car il $correspond avant la nouvelle ligne à la fin de la chaîne. Cacher les trucs supplémentaires dievia la nouvelle ligne ajoutée me semble nécessaire. Est également y///cbeaucoup plus court que length$_et un octet plus court que lengthsans inutile $_.
Heiko Oberdiek
1
@ardnew: J'avais oublié la verbosité de die . Il comprend même imprime le numéro de ligne! Je vais l'utiliser dans ma prochaine mise à jour.
Dennis
3

C, 187 octets

Limites.

  • N'utilisez pas de chaînes de saisie de plus de 98 caractères :)

Version golfée

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;}

Version non golfée

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
la source
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

L'entrée passe par stdin. Je vais l'expliquer s'il y a une demande, mais il ne semble pas que je vais gagner de toute façon.

Fraxtil
la source
1

Perl, 157 154

Edit : -3 grâce à la suggestion 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}

Cela m'a pris du temps (allumé et éteint, bien sûr, pas 5 jours ;-)), et l'idée d'algorithme était initialement insaisissable (même si je pensais qu'il était là), mais finalement (et soudainement), tout est devenu clair.

Si la longueur de la chaîne est multiple de la longueur du motif, et même si la chaîne ne commence pas par le début du motif, la concaténation de la chaîne avec elle-même produira un motif à la place de la concaténation (imaginez la répétition infinie d'un mot sur un ruban circulaire - l'endroit de le soudage n'est pas important). Donc, l'idée est de couper la ligne à plusieurs longueurs d'unité et de concaténer l'original. Le résultat, même pour la chaîne contenant le mauvais caractère, est garanti pour correspondre au modèle au moins une fois. À partir de là, il est facile de trouver la position du personnage incriminé.

La première ligne est empruntée sans vergogne à la réponse 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
}
user2846289
la source
1
bon travail. je pense que vous pouvez remplacer /.{$n}/;$_=$&.$_;pars/.{$n}/$&$&/;
ardnew
1

JavaScript (ES6) - 147 133 136 Caractères

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))

Attend que la chaîne à tester soit dans la variable set renvoie le résultat à la console.

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.
   }         
 );

Cas de test 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))

Les sorties

16 2

Cas de test 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))

Les sorties

8 3

Cas de test 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))

Les sorties

1 1

Cas de test 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))

Les sorties

4 2

Cas de test 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))

Les sorties

0 1

Cas de test 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))

Les sorties

6 1
MT0
la source
Malheureusement, cette approche échoue si, par exemple, s="xyxy\nyyxy". Pour la deuxième ligne, match[4]sera yy; ça devrait être juste y.
Dennis
Retravaillé et raccourci de 14 caractères.
MT0
Très agréable! J'avais essayé le même deuxième regex à un moment donné, mais j'ai ajouté le motif minimal deux fois au lieu du maximum (et, par conséquent, a échoué misérable). Un problème mineur: le premier regex rendra compte ababdu modèle de ababaababa; vous devez utiliser ^…$.
Dennis
/^…\n/fonctionne ou/^…$/m
MT0
1
Il n'a peut-être pas besoin du début ^(du moins, il ne l'est pour aucun des 6 cas de test que j'ai énumérés - mais il y a probablement un contre-exemple où il le fait, je l'ai donc laissé).
MT0