Der FizzBuzz-ish String Matcher

25

Angenommen, Sie haben eine Zeichenfolge wie die folgende:

abaabbbbbaabba

Zählen Sie, wie oft ein bestimmtes Zeichen in der Eingabezeichenfolge angezeigt wird, jedoch nur, wenn das Zeichen nur einmal hintereinander angezeigt wird . Zum Beispiel, wenn das Zeichen ist a,

abaabbbbbaabba
^ x      x   ^

Die Summe wäre 2 (die aawürde nicht zählen, weil die azweimal hintereinander erscheint).

Wie hängt das mit FizzBuzz zusammen?

Wenn das Zeichen 3-mal (oder ein Vielfaches von 3-mal) in einer Reihe oder 5-mal (oder ein Vielfaches von 5-mal) in einer Reihe vorkommt, wird der Zähler dekrementiert . Wenn es ein Vielfaches von 3 und 5 ist, wird der Zähler immer noch inkrementiert. Denken Sie daran, dass der Zähler ebenfalls erhöht wird, wenn das Zeichen nur einmal in einer Reihe vorkommt, und ignoriert wird, wenn das Zeichen mehrmals in einer Reihe vorkommt (außer in den oben beschriebenen Situationen).

Um es noch einmal zusammenzufassen a:

input            counter (explanation)

a                 1 (single occurence)
aaa               -1(multiple of 3)
aaaaa             -1(multiple of 5)  
aaaaaaaaaaaaaaa   1 (multiple of 15)
aa                0 (none of the above)

aba               2 (two single instances)
aaba              1 (one single occurence(+1) and one double occurence(ignored))
aaaba             0 (one single occurence(+1) and one triple (-1)
aaaaaa            -1 (six is a multiple of three)

Referenz (ungolfed) Implementierung in Java:

import java.util.Scanner;
import java.util.regex.*;

public class StrMatcher {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in); //Scanner to get user input
        int total = 0;//Running total of matches

        System.out.println("Enter a string: ");
        String strBeingSearched = sc.nextLine(); //String that will be searched

        System.out.println("Enter string to match with: ");
        String strBeingMatched = sc.nextLine(); //Substring used for searching

        //Simple regex matcher
        Pattern pattern = Pattern.compile("(" + strBeingMatched + ")+");
        Matcher matcher = pattern.matcher(strBeingSearched);

        while(matcher.find()){  //While there are still matches

            int length = matcher.end() - matcher.start();
            int numberOfTimes = length/strBeingMatched.length();//Calculate how many times in a row the string is matched

            if((numberOfTimes == 1)||((numberOfTimes % 3 == 0) && (numberOfTimes % 5 == 0))){
                total++; //Increment counter if single match or divisible by 15
            } else if((numberOfTimes % 3 == 0)||(numberOfTimes % 5 == 0)) {
                total--; //Decrement counter if divisible by 3 or 5 (but not 15)
            }

            strBeingSearched = strBeingSearched.substring(matcher.end());
            matcher = pattern.matcher(strBeingSearched); //Replace string/matcher and repeat
        }

        System.out.println(total);
    }   
}
  • Die zu durchsuchende Zeichenfolge kann beliebig lang sein, das Muster besteht jedoch nur aus einem einzelnen Zeichen.
  • Keine der Zeichenfolgen enthält reguläre Sonderzeichen.
  • Das ist ; kürzestes Programm in Bytes gewinnt.
  • Keine Standardlücken.
Daniel M.
quelle
3
Es wäre nützlich, wenn Sie ein paar weitere Testbeispiele bereitstellen könnten. Insbesondere solche, bei denen die Sequenz mehr als einen Buchstaben enthält.
Reto Koradi
Ich habe ein paar Fälle hinzugefügt - hoffentlich hilft das. Sagen Sie mir, wenn ich mehr Fälle brauche - es ist mein erstes Mal in PPCG.
Daniel M.
Ich werde die Anforderungen so ändern, dass die Sequenz nur ein einzelnes Zeichen ist, da die Implementierung ziemlich gleich ist, aber weniger verwirrend.
Daniel M.
Dies ist wie bei der 1-spärlichen Frage, jedoch mit dem Zusatz
FizzBuzz

Antworten:

32

Funktion , 1840 Bytes

Verdammt, diese Sprache ist nicht golffähig.

Dieses Programm erwartet, dass das erste Zeichen der Eingabe das zu suchende Zeichen und der Rest der Eingabe die zu durchsuchende Zeichenfolge ist. Dies bedeutet, dass in der Eingabe (und damit in der Ausgabe 1) aaabanach gesucht wird . Sie können sie mit einem Zeilenumbruch oder einem Leerzeichen ( ) trennen, aber nur, weil der zusätzliche Zeilenumbruch / Leerzeichen keine Auswirkungen auf die Ausgabe hat.aaabaa aaba

Wie immer erhalten Sie ein ansprechenderes Rendering (ohne Zeilenabstand), wenn Sie es $('pre').css('line-height',1)in Ihrer Browserkonsole ausführen .

      ┌───┐
      │╓─╖└─────────────┐
      └╢³╟┐    ┌─────┐ ┌┴┐╓─╖
┌─────┐╙─╜└────┤┌─╖ ┌┴╖│┌┘║¹║
│     ├───────┐└┤²╟─┤·╟┘│ ╙┬╜╔═══════╗
│    ┌┴╖╔═╗┌─╖├┐╘╤╝ ╘╤╝┌┘  └┬╢2097151║
│    │♭║║5╟┤%╟┘└─┴──┐│┌┘┌───┘╚═══════╝
│    ╘╤╝╚═╝╘╤╝╔═╗┌─╖│││┌┴┐┌────┐
│    ┌┴╖   ┌┘ ║3╟┤%╟┘││└┬┘│╔══╗└┐
│  ┌─┤·╟─┐ │  ╚═╝╘╤╝ │└┐  │║21╟┐│
│  │ ╘╤╝ ├─┘┌─────┘  └┐└┐ │╚══╝│└─┐
│ ┌┴╖┌┴╖┌┴╖┌┴╖┌─╖    ┌┴╖│ │┌─╖┌┴─╖│
│┌┤·╟┤?╟┤?╟┤?╟┤+╟────┤³║│ └┤²╟┤>>║└──┐
││╘╤╝╘╤╝╘╤╝╘╤╝╘╤╝    ╘╤╝│  ╘╤╝╘╤═╝╓─╖│
││ │ ┌┴╖┌┴╖┌┴╖┌┴╖╔═╗ ┌┴╖│  ┌┴╖ ├──╢²╟┤
││ └─┤·╟┤·╟┤?╟┤·╟╢1║┌┤·╟┘  │♯║┌┴╖ ╙─╜│
│└──┐╘╤╝╘╤╝╘╤╝╘╤╝╚═╝│╘╤╝   ╘╤╝│¹║┌───┘
└──┐│╔╧╗ └┬─┘ ┌┴╖   │┌┴─╖   │ ╘╤╝│
   ││║1║ ┌┴┐┌─┤?╟───┴┤>>╟┐ ┌┴╖┌┴╖│
   ││╚═╝ └┬┘│ ╘╤╝    ╘══╝│┌┤?╟┤=║│
   │└────┐│╔╧╗     ┌─────┘│╘╤╝╘╤╝│
╔═╗└────┐│├╢0║╔══╗┌┴╖┌─╖ ╔╧╗   └─┘
║ ║     │└┘╚═╝║21╟┤×╟┤♯╟┐║0║
╚╤╝     └──┐  ╚══╝╘═╝╘═╝│╚═╝
 │┌──┴────╖└────────────┘
 ││int→str║
 │╘══╤════╝
┌┴─╖┌┴╖┌─╖╔╗
│>>╟┤³╟┤¹╟╢║
╘═╤╝╘═╝╘═╝╚╝
╔═╧╗
║21║
╚══╝

(1840 Bytes bei Codierung als UTF-16.)

Erläuterung

  • ¹ Gibt das erste Zeichen einer Zeichenfolge zurück.
  • ²Zählt die Anzahl der Vorkommen eines Zeichens am Anfang einer bestimmten Zeichenfolge. Wenn Sie beispielsweise das Zeichen aund die Zeichenfolge angeben aaba, wird 2 zurückgegeben. Für aund baawird 0 zurückgegeben.
  • ³ruft ²auf, um die Anzahl der Zeichen zu Beginn zu ermitteln, überprüft, ob die Zahl durch 3 und 5 teilbar ist und ob sie gleich 1 ist, und ermittelt das richtige Inkrement / Dekrement. Es wird auch ein zusätzliches Zeichen vom Anfang der Zeichenfolge entfernt (z. B. wenn aaabba3 + 1 = 4 Zeichen entfernt werden, wird angegeben ba). Dann ruft es sich rekursiv mit der kürzeren Zeichenfolge auf und fügt das Ergebnis hinzu.
  • Das Hauptprogramm ruft ¹auf, um das erste Zeichen aus der Eingabe zu entfernen, und ruft ³mit diesem Zeichen und dem Rest der Zeichenfolge als separate Argumente auf.
Timwi
quelle
10
Ich werde Funciton niemals nicht empfehlen.
Orlp
14

CJam, 40 36 35 32 30 Bytes

0llcf=e`::*{(_g+Y13515Yb+=(+}/

Danke an @ MartinBüttner für das Golfen ab 1 Byte!

Vielen Dank an @AndreaBiondo für das Abschlagen von 2 Bytes und den Weg für weitere 3 Bytes!

Probieren Sie es online im CJam-Interpreter aus .

Wie es funktioniert

0          e# Push a 0 (accumulator).
l          e# Read a line from STDIN.
lc         e# Read a second line and keep only the first character.
f=         e# Check each character from the first line for equality.
           e# This results in 1 for the specified character and 0 for others.
e`         e# Perform run-length encoding.
::*        e# Multiply each element by its number of repetitions.
{          e# For each remaining integer I:
  (_!      e#   Subtract 1, copy and push sign(I-1).
  +        e#   Add the results.
           e#     If I == 0, I-1 + sign(I-1) =  -1 + -1 = -2.
           e#     If I == 1, I-1 + sign(I-1) =   0 +  0 =  0.
           e#     If I >= 2, I-1 + sign(I-1) = I-1 +  1 =  I.
  Y        e#   Push 2.
  13515Yb  e#   Convert 13515 into the array of its binary digits.
  +        e#   Concatenate 2 and the array.
           e#   This pushes [2 1 1 0 1 0 0 1 1 0 0 1 0 1 1].
  =        e#   Retrieve the digit at (index I-1 + sign(I-1))%15.
           e#     If I == 0, this pushes 1.
           e#     Else, if I == 1, this pushes 2.
           e#     Else, if I%15 == 0, this pushes 2.
           e#     Else, if I%3==0 or I%5==0, this pushes 0.
           e#     Else, this pushes 1.
  (        e#   Decrement the result.
  +        e#   Add it to the accumulator.
}/         e#
Dennis
quelle
Sie können weitere 2 Bytes mit einer basiscodierten Nachschlagetabelle und modularer Indizierung speichern: llcf=e`::*0-{(_!\6563282Zb:(=}%1bbeträgt 33 Bytes.
Andrea Biondo
@AndreaBiondo Das hat tatsächlich 3 Bytes gespart. Vielen Dank!
Dennis
7

C 160 126 125 119 114 109 104 100 Bytes

main(int q,char **z){int i=0,t=0,s=0,a=z[1][0],c;do{if((c=z[2][i])!=a){s+=(!!t)*((t==1)-!(t%3)-!(t%5)+3*!(t%15));t=0;}else{++t;}++i;}while(c);printf("%d\n",s);}

Kann wahrscheinlich verbessert werden ... Dies nimmt Eingaben von Befehlszeilenargumenten entgegen (erstes Argument ist Muster, zweites ist Zeichenfolge). Unterstützt nicht die Suche nach dem Muster NULL char (\ x00).

EDIT ** 126 125 119 114 109 104 100 Bytes **: Nach Einbeziehung von Dennis 'Vorschlägen und einigen zusätzlichen Ideen (Klausel else entfernt, die while-Anweisung in einer einzigen Anweisung kombiniert und anstelle von! = Die Subtraktion verwendet). Außerdem wurde ein zusätzliches Semikolon in der for-Schleife entfernt (das war eigentlich ein Teil von Dennis 'Vorschlag). Noch mehr verkürzt durch Entfernen der Variablen 'i' und 'a'.

t,s;main(c,z)char**z;{for(;c;t++)if((c=*z[2]++)-*z[1])s+=!!t*((t<2)-!(t%3)-!(t%5)+3*!(t%15)),t=-1;printf("%d",s);}

Die Operatoren if und negation ('!') Wurden entfernt, indem der ternäre Operator missbraucht wurde. Komprimierte die Modularitätsprüfungen mit diesem bitweisen 'UND'-Trick und setzte den (t <2) -Vergleich in die ternären Operatoren. Ersetzt !! t * (...) durch Verschieben !! t in den ternären Operator, sodass ich Klammern entfernen kann.

Mann, ich möchte es wirklich unter die 100-Byte-Marke bringen: S

t,s;main(c,z)char**z;{for(;c;)(c=*z[2]++)-*z[1]?s+=t%15?t%3&&t%5?t<2:-1:!!t,t=0:t++;printf("%d",s);}

TENTATIVE Lösungen: Ich bin nicht sicher, ob diese als gültig angesehen werden, aber ich kann 93 Zeichen erreichen, wenn ich Exits anstelle von printf ("% d", s) verwende. Aber dann wäre die Ausgabe nicht sichtbar, sondern ein Rückkehrcode. Wenn die Ausgabe wirklich notwendig ist, kann ich sie auch auf 98 Bytes reduzieren, aber es würde auch das Drucken aller Zwischenwerte von s vor der endgültigen Antwort erfordern ...

Tob Ernack
quelle
3
Willkommen bei Programming Puzzles & Code Golf! Ich habe es nicht gründlich getestet, i,t,s,a;main(c,z)char**z;{a=*z[1];while(c){if((c=z[2][i])!=a)s+=(!!t)*((t<2)-!(t%3)-!(t%5)+3*!(t%15)),t=0;else++t;++i;}printf("%d",s);}sollte aber genauso gut funktionieren (und es ist 23 Bytes kürzer).
Dennis
Oh, eine schöne Sache, wenn man die if () {} - Klausel in eine einzige Anweisung verwandelt!
Tob Ernack
Noch ein paar Bytes: Wenn du mainmit for(a=*z[1];c;i++)anfängst, brauchst du das {}um das if ... else nicht.
Dennis
4

Ruby, 111 103 96 Bytes

->s,m{s.chars.chunk{|x|x}.reduce(0){|x,(c,g)|l=g.size
x+(c!=m ?0:l<2||l%15<1?1:l%3*l%5<1?-1:0)}}

Diese Herausforderung wurde für Ruby's gemacht Enumerable#chunk, also musste ich dies posten. :)

Online-Test: http://ideone.com/pG4mAn

Der Code ist ziemlich einfach. Hier ist eine besser lesbare Version: http://ideone.com/ub3siA .

Cristian Lupascu
quelle
4

Python 3, 361, 300, 296, 263, 256, 237, 229, 188, 178 , 164 Bytes.

Dank Vaultah von SOPython wurden 15 Bytes eingespart.
9 Bytes dank Joe Kington von SOPython gespeichert.
11 Bytes dank DSM von SOPython eingespart.

Dies ist das erste Mal, dass ich eine Antwort sende, daher bin ich sicher, dass dies viel kürzer sein könnte. Die Testzeichenfolge wird als erste Antwort auf die Eingabe und das Suchzeichen als zweite Antwort verwendet.

t=input()
m=input()
c=u=0
g=iter(t)
while g:
 r=next(g,0)
 if r==0:print(c);g=0
 while r==m:u+=1;r=next(g,0)
 if u:b=u%3<1;v=u%5<1;c+=((0,-1)[b|v],1)[u<2or b&v];u=0

Ungolfed-Version:

import sys
test = sys.argv[1]
match_char = sys.argv[2]
counter = char_counter = 0
char_generator = (c for c in test)
while char_generator:
    try:
        char = next(char_generator)
    except StopIteration:
        print(counter)
        break
    while char == match_char:
        char_counter += 1
        try:
            char = next(char_generator)
        except StopIteration:
            break
    if char_counter == 0:
        continue
    counter += 1 if char_counter == 1 or (char_counter % 3 == 0 and char_counter % 5 == 0) else -1 if char_counter % 3 == 0 or char_counter % 5 == 0 else 0
    char_counter = 0

Ich habe festgestellt, dass einer der Testfälle fehlgeschlagen ist.

Morgan Thrapp
quelle
3

Haskell, 120 Bytes

import Data.List
f c=sum.map(v.length).filter((==c).head).group
v 1=1
v n|n%3&&n%5=1|(n%3||n%5)=(-1)|0<1=0
x%y=x`mod`y<1

f macht den Job.

Leif Willerts
quelle
3

Java, 146 152 143 138 139 136 Bytes

  1. Ein Fehler wurde behoben.
  2. Verschobene Operationen, umgeschaltet auf bitweisen Operator für die %3&%5 Überprüfungen .
  3. Verkürzt i<2 Vergleich.
  4. Fehler behoben (%3&%5 Check funktioniert nicht wie gedacht).
  5. Verwendete Multiplikationsverknüpfung, wie in der Ruby-Antwort von @ w0lf zu sehen .

Implementiert als BiFunction<String, String, Integer>in Java 8, lassen Sie mich wissen, ob dies ein vollständiges Programm sein muss (oder ob ich das Programm überhaupt fallen lassen kann)java.util.regex Paketpräfix darunter ablegen kann).

Die Byteanzahl oben enthält nicht die Newline unten, die lediglich zu Formatierungszwecken auf dieser Site hinzugefügt wird.

(a,b)->java.util.regex.Pattern.compile("[^"+b+"]").splitAsStream(a)
.mapToInt(v->v.length()).map(i->i<2?i:i%15<1?1:i%3*i%5<1?-1:0).sum();

Grobe Erklärung:

  1. Wenden Sie Regex mit einem Muster an, das nicht übereinstimmt b, d. H"[^"+b+"]" .
  2. Ruft die Länge jedes Tokens ab (z. B. "a" -> 1 ).
  3. Gelten die gewünschte Zuordnung zu -1, 0und1 .
  4. sum() um eine Antwort zu bekommen.
hjk
quelle
2

Javascript, 206 Bytes

function f(n,e){var t=n.match(new RegExp(e,"g")).length,g=n.match(new RegExp(e+"{2,}","g"));return null!==g&&g.forEach(function(n){t-=n.length,n.length%15==0?t+=1:(n.length%3==0||n.length%5==0)&&(t-=1)}),t}

Erweitert:

function funkyFizzb(n, c) {
    var score = n.match(new RegExp(c, "g")).length; 
    var repeatOccurence = n.match(new RegExp(c + "{2,}", "g"));

    if(repeatOccurence !== null) {
        repeatOccurence.forEach(function(v,i){
            // remove multiple occurrence counts
            score -= v.length;

            if(v.length % 15 == 0) {
                score += 1;
            }

            else if(v.length % 3 == 0 || v.length % 5 == 0) {
                score -= 1;
            }
        });
    }

    return score;
};

Erläuterung:

Ich verwende Regex, um zu zählen, wie oft ein Zeichen insgesamt erscheint, und subtrahiere dann alle Male, die es in Gruppen auftrat. Zum Schluss gehe ich die Gruppen durch und mache das Fizz Buzz Increment / Decrement.

Besteht die in der Frage angegebenen Testfälle:

funkyFizzb("aaa", "a") => -1

und so weiter

ich meine es ernst
quelle
Entfernen Sie den Alias new, use execanstelle von matchund length, und Sie sollten gut sein.
Mama Fun Roll
2

Perl, 82 65 63 59 Bytes

58 Byte + 1 Byte Befehlszeilenparameter

Nicht besonders kurz, aber es ist ein Anfang - wird ihn weiter verkürzen.

$l=y///c,$i+=!($l>1&&$l%15)||-!($l%3*$l%5)for/$^I+/g;$_=$i

Angenommen -i, Sie geben der Eingabezeichenfolge die folgende Beispielverwendung:

echo "aaabaaa" | perl -pi"a" entry.pl
Jarmex
quelle
0

Pyth, 32 Bytes

so nah! Noch 2 Bytes, um Dennis 'exzellenten CJam-Eintrag zu binden

s.b?qYz?tN@+,0_1 1+}3PN}5PN1Zrw8

Testen Sie es online

Brian Tuck
quelle
0

Gawk, 140

p=$2{b="[^"$1"]";for($0=2;$i-->0;){sub("^"b"*",_,p);p=substr(p,$++i=match(p,b))}for($i=length(p);$++j;)s+=$j%5?$j%3?$j<2:-1:$j%3?-1:1}$0=s""

Eingabe wie folgt: "char space string"

echo "x axxbxcxdexxxfffghixxj" | awk 'p=$2{b="[^"$1"]";for($0=2;$i-->0;){sub("^"b"*",_,p);p=substr(p,$++i=match(p,b))}for($i=length(p);$++j;)s+=$j%5?$j%3?$j<2:-1:$j%3?-1:1}$0=s""'

Ungolfed

p=$2{
    #i=j=s=0                # make reusable
    b="[^"$1"]";           # pattern "not matching char"
    $0=2;                  # help starting the while loop
    while($i-->0){         # match didn't return -1; dec stack top
        sub("^"b"*",_,p);  # remove not matching chars at head of string
        $++i=match(p,b);   # push index of first occurence of not matching char
        p=substr(p,$i)     # remove matching chars from head of string
    };
    $i=length(p);          # get last value
    while($++j)            # sometimes last value on stack is 0
        s+=$j%5?$j%3?$j<2:-1:$j%3?-1:1

        # if $j%5!=0
        #   if $j%3!=0     (not divisible by 5 AND 3)
        #     s+=($j==1)   (single character)
        #   else           (divisible by 3 but not by 5)
        #     s-=1
        # else             (divisble by 5)
        #   if $j%3!=0
        #     s-=1         (divisible by 5 but not by 3)
        #   else
        #     s+=1         (divisible by 3 AND 5)

}$0=s"" # output
Cabbie407
quelle
0

Pyth, 27 Bytes

sm|!JPdx,02+}3J}5JhMf}zTrw8

Testsuite

Eingabe in das Formular zB:

a
aaaba

Erläuterung:

sm|!JPdx,02+}3J}5JhMf}zTrw8
                               z = input() (The match character)
                         w     input() (The string)
                        r 8    Run length encode
                    f}zT       Filter for the runs z is in.
                  hM           Take their lengths
 m|                            Map (d) to the logical or of
    Pd                         Find all prime factors of the current run length
   J                           Save them in J
  !                            Take the logical negation. This will be 1 if
                               d is 1, and 0 otherwise.
           +}3J                If d wasn't 1, add up 1 if 3 is in J
               }5J             and 1 if 5 is in J.
       x,02                    Then, take the index of the result in [0,2]
                               so 0 -> 0, 2 -> 1, 1 -> -1 (not found)
s                              Sum up the values for each run.
isaacg
quelle