Ceylan 386 333 252 230 222 216 171 153 131 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)]+"...";
Original non golfé:
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]+"...";
}
Cela représente 386 octets / caractères. Quelques fonctionnalités intéressantes ici:
La x[y:z]
syntaxe est du sucre syntaxique pour x.measure(y, z)
, et renvoie une sous-plage x
commençant y
par la longueur z
- pour les chaînes, il s'agit d'une sous-chaîne. (Il existe également une x[y..z]
syntaxe, qui est une plage allant de l'index y à z, tous deux inclus, ainsi que des plages semi-ouvertes x[...z]
et x[y...]
.)
List.lastIndexWhere
prend un prédicat (ie une fonction prenant un élément de liste et retournant un booléen, ie ici un Callable<Boolean, [Character]>
), et donne l'index du dernier élément de liste où le prédicat est rempli (ou nul, s'il n'est jamais rempli). Comme les chaînes sont des listes, cela fonctionne aussi pour les chaînes.
Le résultat de ceci, spaceIndex
est de type Integer|Null
, ou Integer?
pour faire court - c'est-à-dire qu'il peut être soit un entier ou null
(la seule valeur de type Null
). (Le nom spaceIndex
vient de quand je ne savais pas que -
c'était aussi spécial - je suppose que ce breakIndex
serait mieux.)
Avec exists spaceIndex
nous pouvons vérifier si spaceIndex
est non nul et faire quelque chose de différent alors. (À l'intérieur de ce bloc if, le compilateur sait qu'il n'est pas nul ... sans cela il se serait plaint si j'avais l'habitude spaceIndex
d'accéder à la chaîne.)
Au lieu de la fonction locale, spacePredicate
nous pouvons également utiliser une fonction anonyme
(Character char) => char == ' ' || char == '-'
Cela nous amène à 333 caractères:
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 prochaine optimisation consiste à utiliser des noms de variables et de fonctions plus courts, ce qui nous ramène de 81 octets à 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 fonction prédicat n'a pas besoin de déclarer son type d'argument, ce qui peut être déduit par le compilateur. Idem pour le type de i
(où nous devons encore écrire value
pour le marquer comme une déclaration). Maintenant, cette déclaration est suffisamment courte pour tenir sur une seule ligne, ce qui nous ramène à 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]+"...";
}
Au lieu de e == ' ' || e == '-'
nous pouvons également écrire e in [' ', '-']
(ou e in {' ', '-'}
, c'est un constructeur itérable au lieu d'un tuple). L' in
opérateur est mappé à la méthode Category.contains, ce qui nous amène à l'idée que nous pouvons passer la contains
méthode de ce tuple directement (c'est un appelable prenant n'importe quel objet, donc acceptant également le caractère), sans le passe- (e) => ...
partout (222 octets):
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]+"...";
}
En fait, une autre catégorie contenant les deux mêmes caractères est la chaîne de deux caractères " -"
. (De plus, il contient également ses sous-chaînes, mais cela ne fait pas de mal ici). 216 octets.
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]+"...";
}
Je suppose que nous avons tiré le meilleur parti de cette ligne, passons aux autres ... les deux dernières déclarations de retour ont une certaine similitude que nous pouvons exploiter - elles diffèrent simplement par i
rapport à vs. l-3
, et utilisent i
juste quand elle n'est pas nulle, sinon l-3
. Heureusement, c'est exactement ce pour quoi l' else
opérateur est fait!
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)] + "...";
}
(Les parenthèses semblent être nécessaires ici, tout comme celles qui else
ont une priorité plus faible que [:]
.) Il s'agit de 171 caractères. Maintenant, il i
n'est utilisé qu'une seule fois, nous pouvons donc l'intégrer, ce qui nous amène à 153 caractères:
String t(String s, Integer l) {
if(s.size < l) {
return s;
}
return s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
}
Nous pouvons également remplacer cette if-return-return
combinaison par une combinaison des opérateurs then
et else
en un return
. ( then
renvoie est le deuxième opérande lorsque le premier est vrai, sinon null, ce qui permet ensuite else
de renvoyer son deuxième opérande.) 131 octets (bien que certaines des économies soient les espaces blancs dont nous nous débarrasserons de toute façon):
String t(String s, Integer l) {
return s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
}
Une fonction qui ne contient qu'un seul retour avec une expression peut alternativement être écrite avec la notation "grosse flèche", donnant 123:
String t(String s, Integer l) =>
s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
Supprimer les espaces blancs inutiles nous donne les 111 derniers octets:
String t(String s,Integer l)=>s.size<l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains)else l-3)]+"...";
En complément, voici une fonction qui imprime les exemples de la question (en utilisant le nom t
qui est utilisé après l'étape deux):
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));
}
}