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

7. 1. 2014, Vladimír Klaus, přečteno 2560x

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.