FizzBu​​zz風の文字列マッチャー


25

次のような文字列があるとしましょう:

abaabbbbbaabba

指定した文字が入力文字列に表示される回数をカウントしますが、その文字が連続して表示されるのは1回のみです。たとえば、文字がの場合a

abaabbbbbaabba
^ x      x   ^

合計は2になります(が2回連続しaaa表示されるため、「s」はカウントされません)。

これはFizzBu​​zzとどのように関連していますか?

文字が連続して3回(または3の倍数)、または連続して5回(または5の倍数)出現する場合、代わりにカウンターがデクリメントされます。3 回 5回の両方の倍数である場合、カウンターはまだインクリメントされます。文字が1行に1回しか表示されない場合もカウンターがインクリメントされ、文字が他の行に何度も表示される場合は無視されることに注意してください(上記の状況を除く)。

要約すると、一致する文字列がの場合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)

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);
    }   
}
  • 検索される文字列の長さは任意ですが、パターンは1文字のみです。
  • どちらの文字列にも正規表現の特殊文字は含まれません。
  • これはです。バイト単位の最短プログラムが優先されます。
  • 標準的な抜け穴はありません。

3
さらにいくつかのテスト例を提供できると便利です。特に、シーケンスに複数の文字がある場合。
レトコラディ

いくつかのケースを追加しました-うまくいけばそれが助けになります。さらにケースが必要な場合は教えてください-PPCGが初めてです。
ダニエルM.

実装はほとんど同じですが、混乱が少ないため、シーケンスが1文字のみになるように要件を変更します。
ダニエルM.

これは、1-スパース質問のようですが、FizzBu​​zzを添加した
ev3commander

回答:


32

機能、1840バイト

くそー、この言語は使用できません。

このプログラムは、入力の最初の文字が検索対象の文字であり、残りの入力が検索対象の文字列となることを想定しています。これは、入力でaaaba検索することを意味しaますaaba(したがって、出力1)。改行またはスペース()で区切ることができますa aabaが、これは余分な改行/スペースが出力に影響を与えないためです。

いつものよう$('pre').css('line-height',1)に、ブラウザコンソールで実行すると、見栄えの良いレンダリング(行間隔なし)を得ることができます。

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

(UTF-16としてエンコードされた場合、1840バイト。)

説明

  • ¹ 文字列の最初の文字を返します。
  • ²特定の文字列の先頭にある文字の出現回数をカウントします。たとえば、文字aと文字列を指定すると、aaba2を返します。との場合abaa0を返します。
  • ³²開始時の文字数を取得するための呼び出しは、その数が3と5で割り切れるかどうか、および1に等しいかどうかを調べ、適切なインクリメント/デクリメントを決定します。また、文字列の先頭から余分な文字を1つ削除します(たとえば、aaabba3 + 1 = 4文字を削除すると、ba)。次に、短い文字列で再帰的に自分自身を呼び出し、結果を追加します。
  • メインプログラムは¹、入力から最初の文字を削除するために呼び出し³、その文字と残りの文字列を別々の引数として呼び出します。

10
私は決してFuncitonを支持しません。
orlp

14

CJam、40 36 35 32 30バイト

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

1バイトのゴルフをしてくれた@MartinBüttnerに感謝します!

@AndreaBiondoに2バイトのゴルフをし、さらに3バイトの道を開いてくれてありがとう!

CJamインタプリタでオンラインで試してください。

使い方

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#

基本エンコードされたルックアップテーブルとモジュラーインデックスを使用して、さらに2バイトを保存できます。33 llcf=e`::*0-{(_!\6563282Zb:(=}%1bバイトです。
アンドレアビオンド

@AndreaBiondoこれは実際に3バイトを節約しました。ありがとう!
デニス

7

C、160 126 125 119 114 109 104 100バイト

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

おそらくより良くすることができます...これはコマンドライン引数から入力を取ります(最初の引数はパターン、2番目は文字列です)。NULL文字(\ x00)のパターンの検索はサポートしていません。

編集** 126 125 119 114 109 104 100バイト**:デニスの提案といくつかの追加のアイデアを組み込んだ後(else節を削除し、whileを1つのステートメントに結合し、!=の代わりに減算を使用)。また、forループの余分なセミコロンも削除しました(実際には、デニスの提案の一部でした)。変数「i」と「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);}

三項演算子を乱用してifおよび否定( '!')演算子を削除しました。ビット単位の「&」にはバグがあるため、ビット単位の「AND」トリックを使用て二重の&& を使用、三項演算子内に(t <2)比較を配置することにより、モジュール性チェックを圧縮しました。!! tを三項演算子に移動して!! t *(...)を置き換え、かっこを削除できるようにしました。

男、私は本当に100バイトのマークの下にそれを取得したいです: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);}

暫定的な解決策:これらが有効と見なされるかどうかはわかりませんが、printf( "%d"、s)の代わりにexit(s)を使用すると、93文字になります。ただし、出力は表示されず、戻りコードになります。出力が本当に必要な場合は、98バイトまで出力できますが、最終的な回答の前にsのすべての中間値を出力する必要があります...


3
プログラミングパズルとコードゴルフへようこそ!完全にはテストしていませんが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);}、同様に機能するはずです(23バイト短くなっています)。
デニス

ああ、if(){}節を1つのステートメントに変換するのは素晴らしいことです。
トブエルナック

さらにいくつかのバイト:あなたが起動した場合mainfor(a=*z[1];c;i++)、あなたが必要としない{}場合は...他の周り。
デニス


4

Pythonの3、361、300、296、263、256、237、229、188、178、164バイト。

SOPythonのvaultahのおかげで15バイト節約されました。
SOPythonのJoe Kingtonのおかげで9バイト節約されました。
SOPythonのDSMのおかげで11バイト節約されました。

回答を提出するのはこれが初めてなので、これはもっと短くなると確信しています。入力に対する最初の応答としてテスト文字列を取り、2番目の応答として検索文字を取ります。

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

ゴルフされていないバージョン:

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

テストケースの1つに失敗していたことがわかりました。


3

Haskell、120バイト

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 仕事をします。


3

Java(登録商標)、146の 152 143 138 139 136バイト

  1. バグを修正しました。
  2. %3&%5チェックのためにビット演算子に切り替えられたシフト操作。
  3. 短縮i<2比較。
  4. バグを修正しました(%3&%5チェックが想定どおりに機能しない)。
  5. @ w0lfのRubyの回答に見られるように、乗算のショートカットを使用しました。

BiFunction<String, String, Integer>Java 8でaとして実装されています。これが完全なプログラムである必要があるかどうか(または、java.util.regex以下のパッケージプレフィックスを削除できる場合)を教えてください。

上記のバイトカウントには、以下の改行は含まれていません。改行は、このサイトで書式設定のために単に追加されたものです。

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

大まかな説明:

  1. パターンと正規表現は適用されません一致b、すなわち"[^"+b+"]"
  2. 各トークンの長さを取得します(例:)"a" -> 1
  3. -10およびに目的のマッピングを適用します1
  4. sum() 答えを得るために。

2

Javascript、206バイト

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}

拡張:

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

説明:

私は正規表現を使用して、文字が表示される合計回数をカウントし、グループから表示されるすべての時間を減算します。最後に、グループを調べて、フィズバズのインクリメント/デクリメントを行います。

質問で指定されたテストケースに合格します。

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

等々


を削除しnew、のexec代わりにmatch、エイリアスを使用lengthしてください。
ママファンロール

2

Perl、82 65 63 59バイト

58バイト+ 1バイトのコマンドラインパラメーター

特に短いわけではありませんが、開始点です-短縮を続けます。

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

-i入力文字列の使用例を以下に示すために使用できると仮定します。

echo "aaabaaa" | perl -pi"a" entry.pl


0

ガウク、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""

「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""'

非ゴルフ

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

0

Pyth、27バイト

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

テストスイート

フォームの入力例:

a
aaaba

説明:

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.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.