07.01.2014, Vladimír Klaus, navštíveno 4695x

ASP.NET/C#

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.

Jak v ASP.NET bezpečně zkrátit text a případně doplnit tečkami

Takto vypadá problematický příklad:

var Text = "Malý text";
var KratsiText = Text.Substring(0, 10); 

Jak v ASP.NET bezpečně zkrátit text a případně doplnit tečkami

Ř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.