07.01.2014, Vladimír Klaus, navštíveno 4718x
Dříve nebo později vás v C# překvapí, jak poněkud hloupě pracuje funkce Substring(). Když totiž zadáte požadovanou délku, která přesahuje délku vlastního textu, skončí to výjimkou.
Takto vypadá problematický příklad:
var Text = "Malý text";
var KratsiText = Text.Substring(0, 10);
Řešení je jednoduché – napíšeme si bezpečnější funkci, která délku ohlídá.
//Bezpečnější varianta, která neskončí výjimkou, pokud je textový
//řetězec kratší než požadovaná délka
public static string LeftStr1(string s, int length)
{
return (s.Length > length) ? s.Substring(0, length) : s;
}
Docela často ale potřebujete textový řetězec nejen zkrátit, ale také nějak ukázat, že došlo ke zkrácení. Nejčastěji se přidávají tři tečky, proto si funkci trochu vylepšíme. A to také tím, aby zkrácený text nekončil uprostřed slova.
//Druhá varianta umožní doplnit v případě zkrácení třeba ještě tečky
public static string LeftStr2(string s, int length, string ending = "") {
int lastDelim;
//pokud bude třeba text zkracovat
if(s.Length > length) {
//nejprve zkrátím text na zadanou délku, dále budu hledat
//oddělovač a zkracovat lépe
s = s.Substring(0, length);
//najdeme poslední mezeru
lastDelim = s.LastIndexOf(" ");
//pokud tam nějaká je, zkrátím to k ní
if(lastDelim > 0) {
s = s.Substring(0, lastDelim);
}
//pokud chci nějaké zakončení, tak ho přidám
if(ending != "") {
s += ending;
}
}
return s;
}
Určitě vás napadá další vylepšení této funkce – třeba moci zadat místo pouhé mezery celou sadu oddělovačů. To se může hodit, pokud jsou v textu pevné mezery, tabelátory apod. Zároveň by bylo ale potřeba, aby se sada oddělovačů nemusela zadávat, stejně tak jako zakončovací řetězec v předchozí variantě.
//Třetí varianta vychází z druhé, pouze umožňuje zadat sadu oddělovačů,
//které se budou hledat. To se může hodit, pokud jsou v textu pevné
//mezery, tabelátory apod.
public static string LeftStr3(string s, int length, string[] delims = null, string ending = "") {
int lastDelim;
//pokud bude třeba text zkracovat
if(s.Length > length) {
//nejprve zkrátím text na zadanou délku, dále budu hledat oddělovač
//a zkracovat lépe
s = s.Substring(0, length);
//pokud nezadám sadu oddělovačů, vytvořím si vlastní sadu o jednom
//prvku, který bude obsahovat mezeru
if(delims == null) {
delims = new string[] {" "};
}
//nyní najdu oddělovač, který je nejblíže konci
lastDelim = -1;
foreach (string delim in delims) {
var pos = s.LastIndexOf(delim);
if(pos>lastDelim) {
lastDelim = pos;
}
}
//pokud tam nějaký oddělovač je, řetězec zkrátím
if(lastDelim > 0) {
s = s.Substring(0, lastDelim);
}
//pokud chci nějaké zakončení, tak ho přidám
if(ending != "") {
s += ending;
}
}
return s;
}
Funkce potom můžete volat třeba takto:
var Text = "Malý text";
//var KratsiText = Text.Substring(0, 10);
var DivnyText = "abcdefghijklmnopqrstuvwxyz";
var SlozitejsiText = "Toto je delší, pokusný text.";
LeftStr1(Text, 6)
LeftStr2(Text, 6)
LeftStr2(Text, 6, "...")
LeftStr2(DivnyText, 6, "...")
LeftStr2(SlozitejsiText, 16, "...")
LeftStr3(Text, 6)
LeftStr3(Text, 6)
LeftStr3(DivnyText, 6)
//tady založíme pole, které bude obsahovat mezeru, čárku a tabelátor
LeftStr3(SlozitejsiText, 16,
new string[] {" ", ",", Convert.ToChar(9).ToString()}, "...")
Asi jste si všimli, že toto chytřejší řešení má oproti originální funkci jednu nevýhodu - neumí vracet část řetězce zprostředka. Ale to se při zkracování zase tak často nepoužívá a jistě si to případně budete umět doprogramovat již sami.