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)]+"...";
Originale 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]+"...";
}
Questo è 386 byte / caratteri. Alcune caratteristiche interessanti qui:
La x[y:z]sintassi è zucchero sintattico per x.measure(y, z), e restituisce un sottogruppo di xpartenza ycon lunghezza z- per le stringhe, questa è una sottostringa. (Esiste anche una x[y..z]sintassi, che è un intervallo dall'indice y alla z, sia inclusivo, sia span semiaperto x[...z]e x[y...].)
List.lastIndexWhereaccetta un predicato (ovvero una funzione che prende un elemento elenco e restituisce un valore booleano, ovvero qui a Callable<Boolean, [Character]>) e fornisce l'indice dell'ultimo elemento elenco in cui è soddisfatto il predicato (o null, se non viene mai adempiuto). Poiché le stringhe sono elenchi, questo funziona anche per le stringhe.
Il risultato di questo, spaceIndexè di tipo Integer|Null, o Integer?in breve - cioè può essere un numero intero o null(l'unico valore di tipo Null). (Il nome spaceIndexderiva da quando non mi rendevo conto che -era anche speciale - immagino breakIndexsarebbe meglio.)
Con exists spaceIndexpossiamo verificare se spaceIndexnon è nullo e fare qualcosa di diverso allora. (All'interno di questo if-block il compilatore sa che è non null ... senza che si sarebbe lamentato se avessi usato spaceIndexl'accesso alla stringa.)
Invece della funzione locale spacePredicatepossiamo anche usare una funzione anonima
(Character char) => char == ' ' || char == '-'
Questo ci porta a 333 caratteri:
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]+"...";
}
La prossima ottimizzazione consiste nell'utilizzare nomi di variabili e funzioni più brevi, il che ci porta da 81 byte a 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]+"...";
}
La funzione predicato in realtà non ha bisogno del suo tipo di argomento dichiarato, che può essere dedotto dal compilatore. Lo stesso vale per il tipo di i(dove dobbiamo ancora scrivere valueper contrassegnarlo come una dichiarazione). Ora quella dichiarazione è abbastanza breve da stare su una riga, portandoci giù a 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]+"...";
}
Invece di e == ' ' || e == '-'possiamo anche scrivere e in [' ', '-'](o e in {' ', '-'}, questo è un costruttore iterabile anziché uno tuplo). L' inoperatore si associa al metodo Category.contains, che ci porta all'idea che possiamo passare containsdirettamente il metodo di quella tupla (è un callable che prende qualsiasi oggetto, quindi accetta anche il carattere), senza il (e) => ...boilerplate (222 byte):
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]+"...";
}
In realtà, un'altra categoria contenente gli stessi due caratteri è la stringa di due caratteri " -". (Inoltre contiene anche le sue sottostringhe, ma non fa male qui). 216 byte.
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]+"...";
}
Immagino che abbiamo ottenuto il massimo da questa linea, passiamo agli altri ... le ultime due dichiarazioni di ritorno hanno una somiglianza che possiamo sfruttare - differiscono solo in ivs. l-3e stanno usandoi proprio quando non è nullo, altrimenti l-3. Fortunatamente questo è esattamente ciò per cui l' elseoperatore è fatto!
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)] + "...";
}
(Le parentesi sembrano essere necessarie qui, come else ha una precedenza inferiore a [:].) Questo è 171 caratteri. Ora iviene usato solo una volta, quindi possiamo incorporarlo, portandoci a 153 caratteri:
String t(String s, Integer l) {
if(s.size < l) {
return s;
}
return s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
}
Possiamo anche sostituire questa if-return-returncombinazione con una combinazione di theneelse operatori in uno return. ( thenrestituisce il secondo operando quando il primo è vero, altrimenti nullo, che quindi consente elsedi restituire il secondo operando.) 131 byte (anche se alcuni dei risparmi sono gli spazi bianchi che elimineremo comunque):
String t(String s, Integer l) {
return s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
}
Una funzione che contiene un solo ritorno con un'espressione può in alternativa essere scritta con la notazione "freccia grassa", dando 123:
String t(String s, Integer l) =>
s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
La rimozione dello spazio bianco non necessario ci dà i 111 byte finali:
String t(String s,Integer l)=>s.size<l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains)else l-3)]+"...";
Come aggiunta, ecco una funzione che stampa gli esempi dalla domanda (usando il nome tche viene usato dopo il secondo passaggio):
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));
}
}