Tìm ký tự lẻ trong một mẫu


20

Đầu vào

Dòng đầu tiên sẽ là một chuỗi nhất định lặp đi lặp lại bất kỳ số lần. Ví dụ, nó có thể được abcabcabcabc, [];[];[];vv Nó có thể được cắt bỏ; ví dụ : 1231231231. Luôn luôn tìm chuỗi ngắn nhất; ví dụ, nếu dòng là 22222, sau đó chuỗi là 2, không 22hay 22222hoặc bất cứ điều gì khác. Chuỗi sẽ luôn được lặp lại ít nhất 2 lần.

Tất cả các dòng tiếp theo sẽ được bù mẫu đó bằng bất kỳ số nào. Ví dụ: nó có thể là:

abcabcabc
cabcabcab
bcabcabca

(bù 1) hoặc có thể là:

abcdefabcdefabcdefabc
cdefabcdefabcdefabcde
efabcdefabcdefabcdefa

(bù 4).

Một trong các ký tự trong đầu vào sẽ sai. (Nó được đảm bảo không nằm trên dòng đầu tiên.) Ví dụ, trong đầu vào này:

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

các 1trên dòng 3 là lẻ một ra.

Đầu ra

Bạn phải xuất tọa độ (dựa trên không, bắt đầu từ tọa độ trên cùng bên trái) của tọa độ lẻ. Ví dụ, trong đầu vào trên, đầu ra tương ứng là 4,2. Bạn cũng có thể xuất 4 2, hoặc "4""2", hoặc thậm chí [[4],[2]], hoặc bất kỳ định dạng nào khác, miễn là bạn có thể cho biết đầu ra là gì.

Các trường hợp thử nghiệm

Đầu vào:

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

Đầu ra: 16,2

Đầu vào:

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

Đầu ra: 8,3

Đầu vào:

...
. .
...

Đầu ra: 1,1

Đầu vào:

ababa
babab
ababb
babab

Đầu ra: 4,2

Đi!


Những ký tự có thể được chứa trong chuỗi? ASCII có thể in được? ASCII? Unicode?
Dennis

@Dennis Just in ASCII (mà về cơ bản có thể được giả định cho bất kỳ thách thức liên quan đến chuỗi, nếu không chúng ta sẽ phải xác định rằng đối với hầu hết các thách thức: P)
tay nắm cửa

Tôi đoán vậy. Tôi đang nghĩ về một cách tiếp cận sẽ cần một char không sử dụng, vì vậy tôi nghĩ tôi sẽ hỏi.
Dennis

Chúng ta có nên kiểm tra trường hợp như thế này: abc/cab/abc- và đầu ra 0 2ở đây?
dùng2846289

@VadimR Không, vì chỉ có một ký tự sẽ sai.
Doorknob

Câu trả lời:


7

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

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

Kịch bản yêu cầu sử dụng -nchuyển đổi, chiếm hai trong số các byte.

Ý tưởng nối thêm hai bản sao của tất cả các lần lặp lại đầy đủ của mẫu đã được lấy từ câu trả lời của MT0 .

Ngược lại với tất cả các câu trả lời khác, cách tiếp cận này cố gắng trích xuất mẫu của dòng đầu vào hiện tại trong mỗi lần lặp; nó sẽ thất bại trên dòng chứa ký tự lẻ (và sử dụng mẫu của dòng trước đó). Điều này được thực hiện để bao gồm trích xuất mẫu trong vòng lặp, quản lý để lưu một vài byte.

Phiên bản ung dung

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

Thí dụ

Đối với trường hợp thử nghiệm

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

đầu ra của phiên bản golf là

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

nghĩa là ký tự lẻ có tọa độ 16,2.

Sự lạm dụng trắng trợn này lợi dụng định dạng đầu ra tự do.

Ngay trước khi thoát, nội dung của một số biến đặc biệt của Perl là:

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

( $nchứa kết quả khớp của mô hình con có thể truy cập thông qua phản hồi \n.)


Khéo léo bắt các đơn vị trả lời. Nó có thể được tối ưu hóa bằng một byte:^((.*?)(.*?))(?=\1+\2$)
Heiko Oberdiek

Tôi chuyển sang ngôn ngữ mà những đứa trẻ nổi tiếng đang sử dụng. Có lẽ có thể được đánh golf xuống hơn nữa; đây là kịch bản Perl đầu tiên của tôi trong hơn một thập kỷ ...
Dennis

2
... Và bạn đã trễ hơn một thập kỷ nếu bạn nghĩ perl là thứ mà những đứa trẻ nổi tiếng đang sử dụng
ardew 26/03 '

Câu trả lời này không nhận được tình yêu mà nó xứng đáng. Trông tôi như người chiến thắng @Doorknob
ardew

8

Perl, 212 191 181 168 byte

$_=<>;/^(((.*?)(.*?))\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,$/}}}
  • Phiên bản này sử dụng một mẹo tối ưu hóa để bắt đơn vị trả lời, được học trong câu trả lời của Dennis .
  • Tối ưu hóa bằng cách sử dụng thuộc tính mà tất cả các dòng có độ dài bằng nhau.
  • Kết thúc dòng cũng cần thiết cho dòng cuối cùng, nếu không chompthay vì chopnên được sử dụng.
  • Tối ưu hóa bình luận của ardew thêm vào.

Phiên bản cũ, 212 byte:

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

Phiên bản bị đánh cắp:

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

Giải pháp và ý kiến ​​tuyệt vời, tôi cần tìm hiểu thêm regex;)
Newbrict

1
đầu tiên choplà không cần thiết - nên được loại bỏ. trận chung kết exit printcó thể được thay thế bằng die(thêm ,$/vào để ẩn những thứ bổ sung (nếu cần)). cũng length$_có thể được thay thế bằngy///c
ardew 25/03/14

@ardnew: Rất cám ơn, tôi đã xóa cái đầu tiên chop, bởi vì $khớp trước dòng mới ở cuối chuỗi. Việc ẩn những thứ bổ sung diethông qua dòng mới được thêm vào dường như là cần thiết đối với tôi. Cũng y///cngắn hơn nhiều length$_và ngắn hơn một byte so với lengthkhông cần thiết $_.
Heiko Oberdiek

1
@ardnew: Tôi đã quên mất tính dài dòng của die . Nó thậm chí bao gồm in số dòng! Tôi sẽ sử dụng nó trong bản cập nhật tiếp theo của tôi.
Dennis

3

C, 187 byte

Hạn chế.

  • Không sử dụng chuỗi đầu vào dài hơn 98 ký tự :)

Phiên bản chơi gôn

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

Phiên bản ung dung

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

2

Con trăn, 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

Đầu vào đi qua stdin. Tôi sẽ giải thích nếu có nhu cầu, nhưng dường như tôi sẽ không giành chiến thắng.


1

Perl, 157 154

Chỉnh sửa : -3 nhờ đề xuất của ardew.

<>=~/^(((.*?).*?)\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}

Tôi đã mất một thời gian (tất nhiên và tắt, tất nhiên, không phải 5 ngày ;-)), và ý tưởng về thuật toán ban đầu khó nắm bắt (mặc dù tôi cảm thấy nó ở đó), nhưng cuối cùng (và đột nhiên) mọi thứ trở nên rõ ràng.

Nếu độ dài chuỗi là nhiều độ dài của mẫu và ngay cả khi chuỗi không bắt đầu bằng bắt đầu mẫu, thì chuỗi nối với chính nó sẽ tạo ra mẫu thay cho nối (hãy tưởng tượng sự lặp lại vô hạn của một từ trên ruy băng tròn - vị trí của hàn không quan trọng). Vì vậy, ý tưởng là cắt đường thẳng thành nhiều đơn vị chiều dài và ghép bản gốc với nó. Kết quả, ngay cả đối với chuỗi chứa ký tự sai, được đảm bảo khớp với mẫu ít nhất một lần. Từ đó trở đi thật dễ dàng để tìm vị trí của nhân vật vi phạm.

Dòng đầu tiên được mượn một cách đáng xấu hổ từ câu trả lời của 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
}

1
công việc tốt đẹp. tôi nghĩ bạn có thể thay thế /.{$n}/;$_=$&.$_;bằngs/.{$n}/$&$&/;
ardew

1

JavaScript (ES6) - 147 133 136 Ký tự

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

Dự kiến ​​chuỗi sẽ được kiểm tra trong biến svà đưa kết quả ra bàn điều khiển.

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

Trường hợp kiểm tra 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))

Đầu ra

16 2

Trường hợp thử nghiệm 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))

Đầu ra

8 3

Trường hợp thử nghiệm 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))

Đầu ra

1 1

Trường hợp thử nghiệm 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))

Đầu ra

4 2

Trường hợp thử nghiệm 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))

Đầu ra

0 1

Trường hợp thử nghiệm 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))

Đầu ra

6 1

Đáng buồn thay, cách tiếp cận này thất bại nếu, ví dụ , s="xyxy\nyyxy". Đối với dòng thứ hai, match[4]sẽ là yy; nó phải được chỉ y.
Dennis

Làm việc lại và rút ngắn 14 ký tự.
MT0

Rất đẹp! Tôi đã thử regex thứ hai rất giống nhau tại một số điểm, nhưng tôi đã nối mẫu tối thiểu hai lần thay vì mẫu tối đa (và do đó, thất bại thảm hại). Một vấn đề nhỏ: regex đầu tiên sẽ báo cáo ababast mẫu của ababaababa; bạn cần sử dụng ^…$.
Dennis

/^…\n/hoạt động hoặc/^…$/m
MT0

1
Nó có thể không cần dẫn đầu ^(ít nhất là nó không có trong bất kỳ 6 trường hợp thử nghiệm nào tôi đã liệt kê - nhưng có lẽ có một ví dụ ngược lại vì vậy tôi đã để nó ở trong đó).
MT0
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.