Pazartesi Mini Golf # 2: Uzun metin kesiliyor


25

Pazartesi Mini Golf: Her Pazartesi yayınlanan (umarım!) Bir dizi kısa mücadelesi.

Birçok web uygulaması (özellikle sosyal medya) otomatik olarak uzun metin pasajlarını keser ve böylece uygulamanın formatına uyuyor. Bu mücadelede, bir metin pasajını otomatik olarak belirli bir uzunlukta kesmek için bir algoritma oluşturacağız.

Meydan okuma

Bu zorluğun amacı iki argüman olan bir program veya işlev yazmaktır:

  • T , kesilecek metin.
  • L , döndürülecek maksimum uzunluk.

Ve aşağıdaki mantıkla kesilen T değerini döndürür :

  • T'nin uzunluğu L'ye eşit veya daha küçükse , kesmeye gerek yoktur. Orijinal dizgiyi döndür.
  • Kesiği T uzunluğu L -2. Bu boşluk veya kısa çizgi içermiyorsa, T'yi tam olarak L -3 karaktere, ardından bir üç noktaya kesilmiş olarak döndürün ....
  • Aksi takdirde, sonucun sonunu son boşluğa veya kısa çizgiye kadar kesin. Bir üç nokta ekleyin ...ve sonucu döndürün .

ayrıntılar

  • T ve L , sırayla veya herhangi bir biçimde alınabilir.
  • 3 < L <2 31 olduğunu varsayabilirsiniz .
  • U + 2026 Yatay Elips'i kullanamazsınız ; üç dönem kullanmalısın.
  • Giriş boşluk veya kısa çizgi ile başlamaz.
  • Giriş, normal boşluklardan başka bir boşluk içermez. (Sekme yok, yeni satır yok, vb.)

Test-vakalar

girişler:

"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

Çıktılar:

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

(Tırnakların yalnızca bunların dizge olduğunu belirtmek için olduğunu; bunların dahil edilmesine gerek olmadığını unutmayın.)

puanlama

Bu , bayt cinsinden geçerli en kısa koddur. Tiebreaker ilk önce son bayt sayısına ulaşan gönderime gidiyor. Kazanan önümüzdeki Pazartesi, 5 Ekim'de seçilecek. İyi şanslar!

Düzenleme: Kazanan için tebrikler, yine 25 byte ile Pyth ile @Jakube !


7
Bu zorluğa verilen cevaplar kendi dillerinde standart bir özellik olmalıdır. Çok sık kötü trunca özelliği olan bir kullanıcı arayüzü görmüştüm ...
Sanchises

1
... "Aksi takdirde, sonucun sonunu son boşluk veya kısa çizgi dahil" NOT "a kadar düzeltin." Sağ?
anatolyg

Metinde herhangi bir sekme olacak mı?
kirbyfan64sos 29:15

@anatolyg Hayır, çünkü son boşluk veya kısa çizgi üç noktadan önce görünecektir.
ETHProductions

@ kirbyfan64sos Hayır. Bunu Ayrıntılar bölümüne ekleyeceğim.
ETHProductions

Yanıtlar:


12

Pyth, 25 bayt

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

Çevrimiçi deneyin: Gösteri veya Test Paketi

Açıklama:

+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


7

Perl, 69 59 52 bayt

51 bayt kodu + 1 bayt komut satırı. Sayısal girişin -i parametresiyle verilmesine izin verildiğini varsayar.

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

Kullanımı:

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

7

Python 2, 78 73 bayt

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

Giriş formatı örnek girişi takip eder.


1
Anarchy Golf'ten tanıdık bir isim. Hoşgeldiniz!
xnor

7

JavaScript (ES6), 123 78 67 61 bayt

Bunu çok fazla kesmeyi beklemiyordum, ancak ekleme / değiştirme kombinasyonunun kesmenin gerekli olduğu her durumu kapsayabildiği ortaya çıktı.

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

İlk argüman dizedir, ikincisi uzunluktur. Uzunluk kontrol optimizasyonu için edc65'e özel teşekkürler!

İşte orijinal kod (123 bayt):

(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
Zeki! +1. İpucu: genellikle .lengthbir dize (T,L)=>T[L]?T.slice(0,L-2).replace(/([ -][^ -]*|.)$/,'...'):Tpuanının uzunluğunu kontrol etmeniz gerekmez 61
edc65

@ edc65 Doh! Uzunluk kontrolünde bir optimizasyon arıyordum, bunu düzeltmenin bir yolu olduğunu düşünmüştüm, ama yönteminiz bana gelmedi. Mükemmel öneri! : D
Mwr247

5 bayttan daha fazla tasarruf etmek için [ -][^ -]ile değiştirebilirsiniz\s\S
Shaun H

Harika çözüm! @ShaunH, o kesinlikle tire için işe yaramazsa yapar?
Jarmex

@ Jarmex Aptal beyin, evet kesinlikle değil.
Shaun H

5

TI-BASIC, 87 bayt

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 çok sayıda string manipülasyon komutuna sahip değildir, bu nedenle son dizini manuel olarak bulmamız gerekir: Eğer dizinde aranacak dizeyi içermiyorsa, inString(0 döndürür. için L, ve daha az yüksek sayıda kayıt veya eşit L-3. Bu sayı Ihala 0 ise, L-3bunun yerine bitiş endeksi olarak kullanırız.

Hesap makinesinin sınırlamaları nedeniyle, bir dizgenin adreslenebilir en büyük endeksi 9999'dur; bu nedenle, bu daha büyük dizeler için başarısız olacaktır.

Hesap makinesinin değişkeni otomatik Iolarak 0'a başlatma davranışına güveniyorum , bu yüzden Içalıştırmadan önce hesap makinenizin hafızasını silin veya silin .


Orada büyük endeksi bulmak için listeyi kullanarak daha kısa çözüm, ama sonra boyut sınırı ~ 500 değil, 9999 olacağını
lirtosiast

4

C # .NET, 187 169 bayt

Hmm ...

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

evet, elbette baytları azaltmak için boşlukları kaldırdım.
Salah Alami

3

Python 2, 105 bayt

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

Denilen

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

1

Groovy, 95 bayt

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]+'...'}

Oldukça basit, muhtemelen daha fazla golf edilebilir



1

T-SQL, 145 bayt

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)))+'...'

kullanımı:

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



1

Ceylon 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 Orijinal:

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]+"...";
}

Bu 386 bayt / karakterdir. Burada bazı ilginç özellikler:

x[y:z]Sözdizimi için sözdizimsel şeker x.measure(y, z)ve bir subrange döndürür xbaşlayan yuzunluktaki z- dizeleri, bu bir alt dize olduğunu. (Orada da x[y..z]a, sözdizimi, yayılma z endeksi y ile ilgili, her ikisi de dahil, hem de yarı açık açıklıklar x[...z]ve x[y...].)

List.lastIndexWherebir yüklem alır (yani bir liste öğesini alan ve bir boole döndüren bir işlev, yani burada a Callable<Boolean, [Character]>) ve yüklemin yerine getirildiği son liste öğesinin indeksini verir (veya hiçbir zaman yerine getirilmezse boş). Dizeler liste olduğundan, bu dizeler için de geçerlidir.

Bunun sonucu spaceIndextürdür Integer|Nullya da Integer?kısaca - yani bir Tamsayı ya da null(türün tek değeri Null) olabilir. (Adı spaceIndex, -bunun da özel olduğunu anlamadığımda geliyor - sanırım breakIndexdaha iyi olurdu.)

İle exists spaceIndexbiz kontrol edebilirsiniz spaceIndexboş olmayan ve daha sonra farklı bir şey yapmak. (Bu if-block içerisinde derleyici boş olmadığını biliyor ... spaceIndexdizeye girersem şikayet etmezdi .)

Yerel işlev yerine spacePredicateanonim bir işlev de kullanabiliriz

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

Bu bizi 333 karaktere getiriyor:

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]+"...";
}

Bir sonraki optimizasyon, bizi 81 bayttan 252'ye düşüren daha kısa değişken ve fonksiyon adlarını kullanmaktır:

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]+"...";
}

Kestirim işlevi aslında, derleyici tarafından çıkarılan argüman türüne gerek duymaz. Türü için de geçerlidir i( valuebeyanname olarak işaretlemek için hala yazmak zorunda olduğumuz yer ). Şimdi bu bildirim bir çizgiye sığacak kadar kısa ve bizi 230'a indirdi:

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]+"...";
}

Bunun yerine e == ' ' || e == '-'biz de yazabiliriz e in [' ', '-'](veya e in {' ', '-'}bu, bir tuple yerine yinelenebilir bir kurucu). inOperatör o demetin geçebilir fikrine bizi yönteme Category.contains, eşleştiren containsolmadan, (o kadar da karakteri kabul, herhangi bir nesne alarak bir çağrılabilir) doğrudan yöntemi (e) => ...boilerplate (222 bayt):

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]+"...";
}

Aslında, aynı iki karakteri içeren başka bir kategori iki karakterli dizedir " -". (Ayrıca alt dizelerini de içeriyor, ancak burası acı vermiyor). 216 bayt.

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]+"...";
}

Bence, başkalarına sırası izin bu hattın en out var galiba ... Son iki dönüş ifadeleri Elimizde kullanabileceğimiz bazı benzerlikler var - onlar sadece farklılık ivs l-3, ve kullanan vardır io boş değil sadece, aksi takdirde l-3. Neyse ki bu tam olarak elseoperatörün yaptığı şey!

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

(Parantezden elsedaha küçük önceliğe sahip olduğu için burada gerekli gibi görünüyor [:].) Bu 171 karakter. Şimdi isadece bir kez kullanılır, bu yüzden satır içi yapabiliriz, bizi 153 karaktere getirir:

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

Bu if-return-returnkombinasyonu bir arada bulunan thenve elseoperatörlerin bir kombinasyonu ile de değiştirebiliriz.return . ( thenbirincisi doğru olduğunda elseikinci işlenendir , aksi takdirde null olur, o zaman ikinci işleyicisini döndürür .`) 131 bayt (tasarrufların bazıları yine de kurtulacağımız beyaz boşluklar olsa da):

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

Bir ifadeyle yalnızca bir dönüş içeren bir işlev, alternatif olarak "şişman ok" gösterimi ile yazılabilir, 123:

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

Gereksiz boşlukların kaldırılması bize son 111 baytı verir:

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

Ek olarak, burada sorudan örnekleri basan bir işlev ( tikinci adımdan sonra kullanılan adı kullanarak ):

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 kabuğu + GNU sed, 65 bayt

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

Bu sed için yapılan bir iş! Ancak uzunluk sınırını aşmak için kabuğa ihtiyacım vardı (belki de Perl daha iyi olurdu). Sed kısım, bitirdiğimiz zaman koşullu sıçramalarla oldukça basit bir diziye genişler:

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

1

Mathematica 192 bayt

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]]&

Olarak adlandırılan

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

1

> <>, 74 bayt

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

Bu çözüm dizginin kesilmesini ve L bu sırayla zaten yığında .

Hizalama sorunlarının neden olduğu 7 israf bayt var, hala bunları atmaya çalışıyor.


1

C # (157):

Dayanarak Salah Alami cevap , ama daha kısa. Dize sınıfı türetilmiştir IEnumerable<char>, bu yüzden yerine T.Contains(" ")||T.Contains("-"), ben kullanımı" -".Any(x=>T.Contains(x)) .

Çözüm:

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

Ungolfed:

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

Güncelleştirme:

SLuck49'un yorumu ile 6 bayt kurtarıldı, Any(T.Contains)bunun yerine kullanıldı Any(x=>T.Contains(x)).


1
İçin .Any(x=>T.Contains(x))doğrudan bir lambda yerine yöntemi kullanabilirsiniz gibi .Any(T.Contains)6 bayt kaydetmek için
SLuck49

@ SLuck49 teşekkürler, cevabımı güncelledi.
Abbas

1

GS2 , 29 bayt

Bu program standart girdi almaktadır. İlk satır dizedir, ikincisi hedef uzunluk numarasıdır.

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 kodunu bazen okumak biraz zor olabilir. :) İşte bazı yorumlar.

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 bayt

Önce Kleyguerth'in cevabını kopyaladım, bu yüzden aynı değişken isimleri ...

İpi 2 karakter kısarak kesin, daha sonra işin çoğu regex tarafından yapılır, bir çizgi ya da boşluğun ardından herhangi bir çizgi olmayan ya da bir çizgi olmayan ya da boşluk sonunda "" ile boşluk bırakılır. VEYA dizenin sonundaki tüm karakterler bir çizgi veya "" "içeren bir boşluk değilse dizgenin sonundaki herhangi bir karakteri değiştirin. Kelimelerin içine koymak, regex yazmaktan daha zor

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

Düzenleme: Aslında, dizgenin regex ile eşleşen kısmını kaldırabilir ve sonuna "..." ekleyebilir:

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



0

C # (Visual C # Etkileşimli Derleyici) , 117 bayt

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'nin cevabı üzerine kurulu olan @ Abba's'dan alınmıştır. ContainsGereksiz bir Substringçağrı kullanmak yerine , kesilen dizede kısa çizgi veya boşluk olup olmadığını kontrol etmek için IndexOf işlevini kullanır.

Çevrimiçi deneyin!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.