月曜日のミニゴルフ#2:長いテキストの切り捨て


25

月曜日のミニゴルフ:毎週月曜日に(願わくば!)投稿された一連の短いチャレンジ。

多くのWebアプリケーション(特にソーシャルメディア)は、長いテキストの一部を自動的に切り捨てて、アプリの書式に収まるようにします。この課題では、テキストのパッセージを特定の長さに自動的にトリミングするアルゴリズムを作成します。

チャレンジ

チャレンジの目標は、2つの引数を取るプログラムまたは関数を作成することです。

  • T、切り捨てるテキスト。
  • L、返される最大長。

そして、次のロジックで切り捨てられたTを返します。

  • Tの長さがL以下の場合、切り捨ては不要です。元の文字列を返します。
  • Tを長さL -2に切り捨てます。これにスペースまたはハイフンが含まれていない場合、Tを正確にL -3文字に切り捨てて、その後に省略記号を続けて返し...ます。
  • それ以外の場合は、結果の末尾を最後のスペースまたはハイフンまでトリミングします。省略記号...を追加して、結果を返します。

詳細

  • TおよびLは、任意の順序で任意の形式で使用できます。
  • 3 < L <2 31と仮定できます。
  • U + 2026 Horizo​​ntal Ellipsisは使用できません。3つのピリオドを使用する必要があります。
  • 入力はスペースまたはハイフンで始まりません。
  • 入力には、通常のスペース以外の空白は含まれません。(タブ、改行などはありません)

テストケース

入力:

"This is some very long text." 25
"This-is-some-long-hyphen-separated-text." 33
"Programming Puzzles & Code Golf is a question and answer site for programming puzzle enthusiasts and code golfers." 55 
"abcdefghijklmnopqrstuvwxyz" 20
"a b c" 4
"Very long." 100

出力:

"This is some very long..."
"This-is-some-long-hyphen..."
"Programming Puzzles & Code Golf is a question and..."
"abcdefghijklmnopq..."
"a..."
"Very long."

(引用符は、これらが文字列であることを指定するためのものであり、含める必要はありません。)

得点

これはであるため、バイト単位の最短有効コードが優先されます。Tiebreakerは、最初に最終バイトカウントに達した送信に進みます。勝者は10月5日の次の月曜日に選ばれます。

編集:勝者の25バイトで、再びPythの@Jakubeにおめでとうございます!


7
この課題に対する回答は、それぞれの言語の標準機能である必要があります。あまりにも頻繁に、悪いトランケートを備えたUIを見てきました
...-

1
... "それ以外の場合、最後のスペースまたはハイフンを含めて、" NOT "まで結果の末尾を切り捨てます。右?
アナトリグ

テキストにはタブがありますか?
kirbyfan64sos

@anatolygいいえ。その場合、最後のスペースまたはハイフンが省略記号の前に表示されるためです。
-ETHproductions

@ kirbyfan64sosいいえ。これを詳細セクションに追加します。
ETHproductions

回答:


12

Pyth、25バイト

+WnzK<zeo}@zN" -"-Q2K"...

オンラインで試す:デモンストレーションまたはテストスイート

説明:

+WnzK<zeo}@zN" -"-Q2K"...  implicit: z = input string, Q = input number
        o        -Q2       order the indices N in [0, 1, ..., Q-3] by
         }@zN" -"            z[T] in " -"
                           (hyphen-indices get sorted to the back)
       e                   take the last such number
     <z                    reduce z to length ^
    K                      save this string to K
+WnzK               K"...  print (K + "...") if z != K else only K

4
私の方法のように最後のオフコードトレイル...
mathmandan

7

Perl、69 59 52バイト

51バイトのコード+ 1バイトのコマンドライン。-iパラメーターで数値入力が許可されていると仮定します。

s/.{$^I}\K.*//&&s/(^([^ -]*).|.*\K[ -].*)..$/$2.../

使用法:

echo "This-is-some-long-hyphen-separated-text." | perl -p -i"33" entry.pl

7

Python 2、78 73バイト

t,l=input()
u=t[:l-2]
print(t,u[:max(map(u.rfind,' -'))]+'...')[l<len(t)]

入力形式は入力例に従います。


1
アナーキーゴルフからおなじみの名前。ようこそ!
-xnor

7

JavaScript(ES6)、123 78 67 61バイト

これをそれほど削減できるとは思っていませんでしたが、スプライス/置換コンボは切り捨てが必要なすべてのケースをカバーできることがわかりました。

(T,L)=>T[L]?T.slice(0,L-2).replace(/([ -][^ -]*|.)$/,'...'):T

最初の引数は文字列、2番目は長さです。長さチェックの最適化については、edc65に感謝します!

元のコード(123バイト)は次のとおりです。

(T,L)=>(T.length>L?(S=T.slice(0,L)).slice(0,(m=Math.max(S.lastIndexOf` `,S.lastIndexOf`-`))<0?L-3:Math.min(L-3,m))+'...':T)

4
賢い!+1。ヒント:多くの場合.length、ストリング(T,L)=>T[L]?T.slice(0,L-2).replace(/([ -][^ -]*|.)$/,'...'):Tスコアの長さを確認する必要はありません61
edc65

@ edc65 Doh!私は長さチェックの最適化を探していました。それを減らすための何らかの方法が必要だと思っていましたが、あなたの方法は私には起こりませんでした。素晴らしい提案!:D
Mwr247

に置き換え[ -][^ -]\s\S、さらに5バイトを節約できます
ショーンH

素晴らしい解決策!@ShaunH、彼がそうするなら、それは確かにハイフンのために働かないでしょうか?
Jarmex

@Jarmex愚かな脳、ええ、それはほとんど間違いなくありません。
ショーンH

5

TI-BASIC、87バイト

Prompt L,Str1
For(X,1,L
{inString(Str1," ",X),inString(Str1,"-",X
max(I,max(Ans*(Ans≤L-3->I
End
Str1
If L<length(Ans
sub(Ans,1,I+(L-3)not(I))+"...
Ans

TI-BASICには多くの文字列操作コマンドがないため、最後のインデックスを手動で見つける必要があります。文字列に検索する文字列が含まれていない場合、inString(0を返します。にL、および以下の最大数を記録しL-3ます。その数Iがまだ0の場合、L-3代わりに終了インデックスとして使用します。

計算機の制限により、文字列の最大アドレス可能インデックスは9999です。したがって、これは大きな文字列では失敗します。

変数Iを自動的に0に初期化する電卓の動作に依存しているため、実行するI前に電卓のメモリを削除またはクリアします。


リストを使用して最大のインデックスを見つける短いソリューションがありますが、サイズ制限は9999ではなく
〜500になります。– lirtosiast

4

C#.NET、187169バイト

うーん...

string f(string T,int L){if(T.Length<=L)return T;T=T.Substring(0,L-2);return T.Substring(0,T.Contains(" ")||T.Contains("-")?T.LastIndexOfAny(new[]{' ','-'}):L-3)+"...";}

はい、もちろん、スペースを削除してバイト数を減らしました。
サラアラミ

3

Python 2、105バイト

def t(s,l):a=s[:l-2];return s[:max(a.rfind(' '),a.rfind('-'))]+'...'if' 'in a or'-'in a else a[:-1]+'...'

と呼ばれる

>>> print t("This is some very long text.", 25)
This is some very long...

1

Groovy、95バイト

a={T,L->F=T.size()<=L?T:T[0..L-3]
m=F=~'(.*[- ])'
F==T?F:m?m[0][0].trim()+'...':F[0..-2]+'...'}

かなり簡単で、おそらくさらにゴルフをすることができます



1

T-SQL、145バイト

create proc a(@t varchar(max),@l int)as if LEN(@t)<=@l return @t;set @t = LEFT(@t,@l-3) select LEFT(@t,LEN(@t)-CHARINDEX('-',REVERSE(@t)))+'...'

使用法:

exec a("This is some very long text.", 25) exec a("This-is-some-long-hyphen-separated-text.", 33)



1

セイロン386 333 252 230 222 216 171 153 131 111

String t(String s,Integer l)=>s.size<l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains)else l-3)]+"...";

Ungolfedオリジナル:

String truncate(String text, Integer length) {
    if(text.size < length) {
        return text;
    }
    Boolean spacePredicate(Character char) {
        return char == ' ' || char == '-';
    }
    Integer? spaceIndex = text[0:length-2].lastIndexWhere(spacePredicate);
    if(exists spaceIndex) {
        return text[0:spaceIndex] + "...";
    }
    return text[0:length-3]+"...";
}

これは386バイト/文字です。ここでいくつかの興味深い機能:

x[y:z]構文はのためのシンタックスシュガーであるx.measure(y, z)、とのサブレンジ返すxから始まるy長さをz-文字列に対して、これはストリングです。(x[y..z]構文もあります。これは、インデックスyからzまでのスパンであり、両方を含み、ハーフオープンスパンx[...z]およびx[y...]。)。

List.lastIndexWhere 述語を取ります(つまり、リスト要素を取り、ブール値を返す関数、つまり、 Callable<Boolean, [Character]>)、述語が満たされる最後のリスト要素のインデックスを与えます(満たされない場合はnull)。文字列はリストなので、これは文字列でも機能します。

この結果spaceIndexは、type Integer|NullまたはInteger?略して-つまり、Integerまたはnull(typeの唯一の値Null)のいずれかです。(名前spaceIndexは、それ-が特別なものであることに気づかなかったときに由来します。breakIndexます。より良います。)

を使用しexists spaceIndexspaceIndex、null以外であるかどうかを確認し、別の操作を実行できます。(このifブロックの内部では、コンパイラはそれがnullでないことを知っています...spaceIndex文字列にアクセスするためした。)

ローカル関数の代わりに、spacePredicate匿名関数を使用することもできます

(Character char) => char == ' ' || char == '-'

これにより、333文字になります。

String truncate(String text, Integer length) {
    if(text.size < length) {
        return text;
    }
    Integer? spaceIndex = text[0:length-2].lastIndexWhere(
        (Character char) => char == ' ' || char == '-');
    if(exists spaceIndex) {
        return text[0:spaceIndex] + "...";
    }
    return text[0:length-3]+"...";
}

次の最適化は、短い変数名と関数名を使用することです。これにより、81バイト減り、252になります。

String t(String s, Integer l) {
    if(s.size < l) {
        return s;
    }
    Integer? i = s[0:l-2].lastIndexWhere(
        (Character e) => e == ' ' || e == '-');
    if(exists i) {
        return s[0:i] + "...";
    }
    return s[0:l-3]+"...";
}

述語関数は、実際には引数の型を宣言する必要がありません。これは、コンパイラによって推論できます。ivalue宣言としてマークするためにまだ記述しなければならない)のタイプについても同じです。これで、宣言は1行に収まるほど短くなり、230になりました。

String t(String s, Integer l) {
    if(s.size < l) {
        return s;
    }
    value i = s[0:l-2].lastIndexWhere((e) => e == ' ' || e == '-');
    if(exists i) {
        return s[0:i] + "...";
    }
    return s[0:l-3]+"...";
}

代わりにe == ' ' || e == '-'書くこともできますe in [' ', '-'](またはe in {' ', '-'}、これはタプルではなく反復可能なコンストラクタです)。inオペレータは、我々はその組の合格できるという考えに私たちをもたらします方法Category.contains、にマップcontainsすることなく、(それはそうも文字を受け入れて、任意のオブジェクトを取る呼び出し可能である)メソッドを直接(e) => ...定型(222バイト):

String t(String s, Integer l) {
    if(s.size < l) {
        return s;
    }
    value i = s[0:l-2].lastIndexWhere([' ', '-'].contains);
    if(exists i) {
        return s[0:i] + "...";
    }
    return s[0:l-3]+"...";
}

実際、同じ2文字を含む別のカテゴリは2文字の文字列" -"です。(さらに、サブストリングも含まれていますが、ここでは問題ありません)。216バイト。

String t(String s, Integer l) {
    if(s.size < l) {
        return s;
    }
    value i = s[0:l-2].lastIndexWhere(" -".contains);
    if(exists i) {
        return s[0:i] + "...";
    }
    return s[0:l-3]+"...";
}

私たちはこの行を最大限に活用したと思いますが、他のものに目を向けてみましょう...最後の2つのreturn文は利用できるいくつかの類似性を持っています-それらは単にivs. l-3で異なり、iそれがnullでないときだけ使用していますl-3。幸いなことに、これはまさにelseオペレーターの目的です!

String t(String s, Integer l) {
    if(s.size < l) {
        return s;
    }
    value i = s[0:l-2].lastIndexWhere(" -".contains);
    return s[0:(i else l-3)] + "...";
}

(括弧elseは、より優先順位が低いため、ここで必要なようです[:]。)これは171文字です。Now iは1回だけ使用されるため、インライン化して153文字にできます。

String t(String s, Integer l) {
    if(s.size < l) {
        return s;
    }
    return s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
}

また、このif-return-return組み合わせを1つののthenand else演算子の組み合わせに置き換えることもできreturnます。(then最初のオペランドがtrueの場合、returnsは2番目のオペランド、それ以外の場合はnullで、2番目のオペランドelseを返すことができます)。

String t(String s, Integer l) {
    return s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
}

式とともに1つの戻り値のみを含む関数は、代わりに「太い矢印」表記で記述でき、123が得られます。

String t(String s, Integer l) =>
    s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";

不要な空白を削除すると、最後の111バイトが得られます。

String t(String s,Integer l)=>s.size<l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains)else l-3)]+"...";

さらに、質問の例を出力する関数があります(tステップ2の後に使用される名前を使用)。

shared void testTruncate() {
    value testInputs = {
        ["This is some very long text.", 25],
        ["This-is-some-long-hyphen-separated-text.", 33],
        ["Programming Puzzles & Code Golf is a question and answer site for programming puzzle enthusiasts and code golfers.", 55], 
        ["abcdefghijklmnopqrstuvwxyz", 20],
        ["a b c", 4],
        ["Very long.", 100]
    };
    for(input in testInputs) {
        print(t(*input));
    }
}

1

POSIXシェル+ GNU sed、65バイト

sed -re "s/(.{$1}).+/\1/;T;s/(.*)[- ]...*/\1.../;t;s/...$/.../;:"

これはsed向けの仕事です!しかし、長さ制限を取得するにはシェルが必要でした(おそらくPerlの方が良いでしょう)。sed部分はかなり単純なシーケンスに展開され、終了時に条件付きジャンプが行われます。

s/(.{$1}).+/\1/
T
s/(.*)[- ]...*/\1.../
t
s/...$/.../
:

1

Mathematica 192バイト

t=With[{r=StringTake[#,Min[#2-2,StringLength[#]]],p={"-",Whitespace},e="..."}, 
  Which[StringLength[#]<=#2,#,StringFreeQ[r,p],StringDrop[r,-1]<>e,
   True,StringTake[r,Max[StringPosition[r,p]]-1]<>e]]&

と呼ばれる

t["This is some very long text.", 25]

1

> <>、74バイト

l$-:1)?\~r05.
/?=0:~$<-1
\}:0=  ?\::"- "@=@=+?
>~"..."r\}
/!?     <
>ol?!;

このソリューションでは、文字列を切り捨てて、 L既にスタック上にある必要があります。

アライメントの問題が原因で7バイトが無駄になっていますが、それでもそれらをゴルフしようとしています。


1

C#(157):

Salah Alami回答に基づきますが、短いです。文字列クラスから派生しIEnumerable<char>、その代わりにT.Contains(" ")||T.Contains("-")、I使用" -".Any(x=>T.Contains(x))

溶液:

string f(string T,int L){if(T.Length<=L)return T;T=T.Substring(0,L-2);return T.Substring(0," -".Any(T.Contains)?T.LastIndexOfAny(new[]{' ','-'}):L-3)+"...";}

ゴルフをしていない:

string f (string T, int L)
{
    if (T.Length <= L)
        return T;

    T = T.Substring(0, L - 2);

    return T.Substring(0, " -".Any(T.Contains) ? T.LastIndexOfAny(new[]{' ', '-'}) : L - 3) + "...";
}

更新:

SLuck49のコメントのおかげで、のAny(T.Contains)代わりに6バイトを節約しましたAny(x=>T.Contains(x))


1
.Any(x=>T.Contains(x))あなたは直接のような方法の代わりに、ラムダを使用することができます.Any(T.Contains)6バイト救うために
SLuck49

@ SLuck49ありがとう、私の答えを更新しました。
アッバス

1

GS2バイト

このプログラムは標準入力を使用します。最初の行は文字列で、2番目の行はターゲットの長さの数値です。

2a 0e 56 3c 40 a0 74 20 22 22 04 5d 2e 2a 3f 5b
20 2d 5d 7c 2e 07 2e 2e 2e 9d 20 e4 35

GS2コードは読みにくい場合があります。:)ここにいくつかの解説があります。

2a         # lines - split input on newlines yielding a two element array
0e         # extract-array - pop array, push both elements 
56         # read-num - convert length string to number
3c         # take - truncate the string to specified length
40         # dup - duplicate truncated string on stack
a0         # junk1 - push the last popped value, the un-truncated string
74         # ne - test for inequality
    20     # reverse string
    22 22  # tail tail - remove first two characters

    # regex replace first occurrence of ".*?[ -]|." with "..."
    04 5d 2e 2a 3f 5b 20 2d 5d 7c 2e 07 2e 2e 2e 9d 

    20     # reverse string
e4         # block5 - make a block out of last 5 instructions
35         # when - conditionally execute block

1

Groovy、56バイト

Kleyguerthの回答を最初にコピーしたため、同じ変数名が...

文字列を2文字で切り取ります。その後、ほとんどの作業は正規表現によって行われ、ダッシュまたはスペースの後に、文字列の末尾にあるダッシュまたはスペースではない任意の数の文字を「。」に置き換えます。または、文字列の前にあるすべての文字がダッシュでも「。」のスペースでもない場合、文字列の末尾の文字を置き換えます。正規表現を書くよりも言葉にするのが難しい...

a={T,L->T.size()<=L?T:T[0..L-3].replaceAll("([- ][^ -]*|(?<=[^- ]*).)\$",".")+".."}

編集:実際には、正規表現に一致する文字列の一部を削除し、最後に「...」を追加するだけです。

a={T,L->T.size()<=L?T:T[0..L-3]-~/[- ][^ -]*$|.$/+"..."}



0

C#(Visual C#Interactive Compiler)、117バイト

a=>b=>a.Length>b?a.Substring(0,(" -".Any(x=>a.IndexOf(x,0,b-2)>-1)?a.LastIndexOfAny(new[]{' ','-'},b-2):b-3))+"...":a

@Salah Alamiの回答に基づいている@Abbaに基づいています。Contains不要なSubstring呼び出しを使用する代わりに、IndexOfを使用して、切り捨てられた文字列にハイフンまたはスペースが存在するかどうかを確認します。

オンラインでお試しください!

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