Jak obciąć ciąg .NET?

406

Chciałbym obciąć łańcuch tak, aby jego długość nie była dłuższa niż podana wartość. Piszę do tabeli bazy danych i chcę się upewnić, że wartości, które piszę, spełniają ograniczenie typu danych kolumny.

Na przykład byłoby miło, gdybym mógł napisać:

string NormalizeLength(string value, int maxLength)
{
    return value.Substring(0, maxLength);
}

Niestety powoduje to wyjątek, ponieważ maxLengthgeneralnie przekracza granice ciągu value. Oczywiście mógłbym napisać funkcję taką jak poniżej, ale miałem nadzieję, że coś takiego już istnieje.

string NormalizeLength(string value, int maxLength)
{
    return value.Length <= maxLength ? value : value.Substring(0, maxLength);
} 

Gdzie jest nieuchwytny interfejs API, który wykonuje to zadanie? Czy jest jeden

Steve Guidi
źródło
24
Dla przypomnienia, ciągi są niezmienne, nie można ich obciąć, można jedynie zwrócić ich obciętą kopię. Nitpicky, wiem.
John Weldon,
2
@John Weldon: Prawdopodobnie dlatego funkcja członka nie istnieje - nie jest zgodna z semantyką typu danych. Na marginesie, StringBuilderpozwala obciąć, zmniejszając długość, ale nadal musisz wykonać kontrolę długości, aby uniknąć poszerzenia łańcucha.
Steve Guidi
1
Niezależnie od tego, które wybierzesz rozwiązanie, przed wywołaniem podłańcucha lub uzyskaniem dostępu do właściwości Length należy dodać sprawdzanie pustego ciągu.
Ray
3
@SteveGuidi - Gdyby tak było, nie byłoby funkcji takich jak Trim lub Replace, które borykają się z podobnymi problemami semantycznymi
Chris Rogers
1
@JohnWeldon Konsekwentnie bardziej podstępne niż same Microsoft - z przyjemnością dokumentują, na przykład .Trim()w sposób, który sprawia, że ​​myląco brzmi, jakby mutował ciąg: „Usuwa wszystkie wiodące i końcowe białe znaki z bieżący obiekt String. ”
Mark Amery

Odpowiedzi:

620

Truncate()Niestety nie ma metody na ciąg znaków. Musisz napisać taką logikę. Możesz jednak zawinąć to w metodę rozszerzenia, abyś nie musiał jej wszędzie kopiować:

public static class StringExt
{
    public static string Truncate(this string value, int maxLength)
    {
        if (string.IsNullOrEmpty(value)) return value;
        return value.Length <= maxLength ? value : value.Substring(0, maxLength); 
    }
}

Teraz możemy napisać:

var someString = "...";
someString = someString.Truncate(2);
LBushkin
źródło
5
Świetne rozwiązanie, ale pamiętam, że działa tylko w NET 3.5 i nowszych wersjach. Nie próbuj w NET2.0.
Mistrz Jedi Spooky
7
Tak długo, jak jesteś w VS 2008 i prawdopodobnie VS 2010, możesz to zrobić, nawet jeśli celujesz w .Net 2.0. danielmoth.com/Blog/…
Mark
4
To się nie powiedzie, gdy maxLengthjest wartością ujemną.
Bernard
42
@Bernard, to ma się nie powieść, jeśli maxLength ma wartość ujemną. Każde inne zachowanie byłoby nieoczekiwane.
bojingo
12
Możesz wywoływać metody rozszerzeń dla wartości null.
Joel Malone
127

Lub zamiast operatora trójskładnikowego możesz użyć Math.min

public static class StringExt
{
    public static string Truncate( this string value, int maxLength )
    {
        if (string.IsNullOrEmpty(value)) { return value; }

        return value.Substring(0, Math.Min(value.Length, maxLength));
    }
}
CaffGeek
źródło
10
Sprytny! Oraz następujące wyrażenie jest zoptymalizowany do powrotu odwołanie do oryginalnego napisu: value.Substring(0, value.Length).
Steve Guidi
4
Niestety nie jest zoptymalizowany dla przypadków, w których wartość. Długość jest mniejsza niż MaxLength, co może być częstym przypadkiem w niektórych danych. Również właściwość Length na łańcuchu powinna być pisana wielkimi literami.
jpierson
1
To się nie powiedzie, gdy maxLengthjest wartością ujemną.
Bernard
7
@Bernard, więc wiele rzeczy w ramach ... ale jeśli mogę sprawdzić na to ... I albo trzeba domyślnie maxLengthdo 0lub value.Length; lub muszę rzucić ArgumentOutOfRangeException..., co w tym przypadku ma większy sens i jest już wyrzucone Substring.
CaffGeek
2
Nieco krótszy:return string.IsNullOrEmpty(value) ? value : value.Substring(0, Math.Min(value.Length, maxLength));
user1127860
43

Pomyślałem, że wrzucę swoje wdrożenie, ponieważ uważam, że obejmuje ono wszystkie sprawy, które zostały poruszone przez innych i robi to w zwięzły sposób, który jest nadal czytelny.

public static string Truncate(this string value, int maxLength)
{
    if (!string.IsNullOrEmpty(value) && value.Length > maxLength)
    {
        return value.Substring(0, maxLength);
    }

    return value;
}

To rozwiązanie opiera się głównie na rozwiązaniu Raya i otwiera metodę do zastosowania jako metodę rozszerzenia przy użyciu tego słowa kluczowego, podobnie jak LBushkin w swoim rozwiązaniu.

jpierson
źródło
To się nie powiedzie, gdy maxLengthjest wartością ujemną.
Bernard
15
@Bernard - Nie polecam przekazywania wartości ujemnej dla argumentu maxLength, ponieważ jest to nieoczekiwana wartość. Metoda Substring przyjmuje to samo podejście, więc nie ma powodu, aby poprawiać wyjątek, który zgłasza.
jpierson
Nie sądzę, aby kontrola IsNullOrEmpty była konieczna? (1) Jeśli wartość jest pusta, nie powinno być możliwości wywołania na niej tej metody rozszerzenia. (2) Jeśli wartość jest pustym łańcuchem, sprawdzenie wartości value.Length> maxLength zakończy się niepowodzeniem.
Jon Schneider,
8
@JonSchneider, IsNullOrEmpty jest wymagany, ponieważ jest to metoda rozszerzenia. Jeśli masz zmienną typu string, której przypisano wartość NULL, kompilator nie wstawi testu NULL przed wywołaniem tej metody. Technicznie jest to wciąż metoda statyczna klasy statycznej. Więc: stringVar.Truncate (2) Kompiluje jako: StringExt.Truncate (stringVar, 2);
Jeff B
40

Ponieważ testowanie wydajności jest zabawne: (przy użyciu metod rozszerzenia linqpad )

var val = string.Concat(Enumerable.Range(0, 50).Select(i => i % 10));

foreach(var limit in new[] { 10, 25, 44, 64 })
    new Perf<string> {
        { "newstring" + limit, n => new string(val.Take(limit).ToArray()) },
        { "concat" + limit, n => string.Concat(val.Take(limit)) },
        { "truncate" + limit, n => val.Substring(0, Math.Min(val.Length, limit)) },
        { "smart-trunc" + limit, n => val.Length <= limit ? val : val.Substring(0, limit) },
        { "stringbuilder" + limit, n => new StringBuilder(val, 0, Math.Min(val.Length, limit), limit).ToString() },
    }.Vs();

truncateMetoda była „znacznie” szybciej. #microoptimization

Wcześnie

  • truncate 10 5788 tyknięć, które upłynęły (0,5788 ms) [w powtórzeniach 10K, 5,788E-05 ms na]
  • smart-trunc10 upłynęło 8206 tyknięć (0,8206 ms) [w 10 000 powtórzeń, 8,206E-05 ms na]
  • stringbuilder10 upłynęło 10 1055 tyknięć (1,0557 ms) [w 10 000 powtórzeń, 0,00010557 ms na]
  • concat10 upłynęło 45495 tyknięć (4,5495 ms) [w 10 000 powtórzeń, 0,00045495 ms na]
  • newstring 10 72535 tyknięć, które upłynęły (7,2535 ms) [w 10 000 powtórzeń, 0,00072535 ms na]

Późno

  • truncate44 8835 tyknięć, które upłynęły (0,8835 ms) [w 10 000 powtórzeń, 8,835 E-05 ms na]
  • stringbuilder44 upłynęło 13106 tyknięć (1,3106 ms) [w 10 000 powtórzeń, 0,00013106 ms na]
  • smart-trunc44 14821 tyknięć, które upłynęły (1,4821 ms) [w 10 000 powtórzeń, 0,00014821 ms na]
  • newstring44 upłynęło 144324 tyknięć (14,4324 ms) [w 10 000 powtórzeń, 0,00144324 ms na]
  • concat44 upłynęło 174610 tyknięć (17,461 ms) [w 10 000 powtórzeń, 0,0017461 ms na]

Za długo

  • smart-trunc64 6944 upłynęło (0,6944 ms) [w powtórzeniach 10K, 6,944E-05 ms na]
  • truncate64 7686 tyknięć, które upłynęły (0,7686 ms) [w 10 000 powtórzeń, 7,686E-05 ms na]
  • stringbuilder64 upłynęło 13314 tyknięć (1,3314 ms) [w 10 000 powtórzeń, 0,00013314 ms na]
  • newstring64 upłynęło 177481 tyknięć (17,7481 ms) [w 10 000 powtórzeń, 0,00177481 ms na]
  • concat64 upłynęło 241601 tyknięć (24,1601 ms) [w 10 000 powtórzeń, 0,00241601 ms na]
drzaus
źródło
Dzięki za wszystkie przydatne testy! ... i Linkpad rządzi!
Sunsetquest
nie przejmowałem się tym, że linqpad może to zrobić
jeffissu
38

W .NET 4.0 możesz użyć Takemetody:

string.Concat(myString.Take(maxLength));

Nie przetestowano pod kątem wydajności!

Dylan Nicholson
źródło
27

Możesz użyć LINQ ... eliminuje to konieczność sprawdzania długości łańcucha. Co prawda może nie jest najbardziej wydajny, ale jest fajny.

string result = string.Join("", value.Take(maxLength)); // .NET 4 Join

lub

string result = new string(value.Take(maxLength).ToArray());
oswoić
źródło
2
dlaczego nie jest to akceptowana odpowiedź? Co jest najprostsze: napisanie własnej metody rozszerzenia, którą musisz utrzymywać / dokumentować, lub użycie czegoś WBUDOWANEGO jak. Weź
Don Cheadle
9
@mmcrae Linq może być prostszy, ale jest też znacznie wolniejszy. Mój test porównawczy mówi, że ~ 400 ms dla Linq i tylko ~ 24 ms dla Substring dla 1 miliona iteracji.
Hein Andre Grønnestad
Tego rozwiązania nie należy nigdy używać. Jak powiedziano w dwóch powyższych komentarzach, zawsze istnieje przydział pamięci, nawet jeśli istniejący ciąg nie jest większy niż maksymalna długość. Również jest bardzo wolny.
Kamarey
15

Zrobiłem mój w taki sposób

value = value.Length > 1000 ? value.Substring(0, 1000) : value;
SeanMC
źródło
2
-1; to wcale nie dodaje niczego, co nie było jeszcze w zaakceptowanej odpowiedzi.
Mark Amery
2
@markamery to krótsza alternatywa z mniejszym kodem do napisania i aktualizacji, kiedy trzeba go użyć. Nie podoba ci się Nie używaj go
SeanMC
Szybki, prosty i szybki. Właśnie tego potrzebowałem. Dzięki!
Peter
14

Wygląda na to, że nikt tego jeszcze nie opublikował:

public static class StringExt
{
    public static string Truncate(this string s, int maxLength)
    {
        return s != null && s.Length > maxLength ? s.Substring(0, maxLength) : s;
    }
}

Użycie operatora && sprawia, że ​​jest on nieznacznie lepszy niż zaakceptowana odpowiedź.

Darren
źródło
13

.NET Framework posiada interfejs API do obcinania takiego łańcucha:

Microsoft.VisualBasic.Strings.Left(string, int);

Ale w aplikacji C # prawdopodobnie wolisz tworzyć własne niż polegać na Microsoft.VisualBasic.dll, którego główną racją bytu jest kompatybilność wsteczna.

Joe
źródło
„Program .NET Framework ma interfejs API”, czemu sam się zaprzeczasz. To jest interfejs API VB.NET
Camilo Terevinto,
9
@CamiloTerevinto - to interfejs API dostarczany z .NET Framework, który można wywoływać z dowolnego zarządzanego języka.
Joe
1
Biblioteka DLL VB zawiera wiele dobrych rzeczy. Dlaczego jest tak wielu deweloperów c # przeciwko temu?
Michael Z.
Niestety obecnie nie obsługuje .NET Core. Rzeczywiście, wszystkie Microsoft.VisualBasic.Stringsmoduły .NET Core są dość puste .
Mark Amery
1
Chociaż zgadzam się z komentarzem Joe, nadal nie czuję się dobrze dzwoniąc do czegoś konkretnego dla VB z innych języków. Jeśli w „VB DLL” jest tyle dobrych rzeczy, dlaczego nie umieścić go w jakimś współdzielonym miejscu? Kto wie, co Microsoft zrobi z tymi rzeczami jutro? Przestańcie wspierać czy coś ..
Kamarey
12

Inne rozwiązanie:

return input.Substring(0, Math.Min(input.Length, maxLength));
Marek Malczewski
źródło
6

Wiem, że to stare pytanie, ale oto fajne rozwiązanie:

public static string Truncate(this string text, int maxLength, string suffix = "...")
{
    string str = text;
    if (maxLength > 0)
    {
        int length = maxLength - suffix.Length;
        if (length <= 0)
        {
            return str;
        }
        if ((text != null) && (text.Length > maxLength))
        {
            return (text.Substring(0, length).TrimEnd(new char[0]) + suffix);
        }
    }
    return str;
}

var myString = "hello world"
var myTruncatedString = myString.Truncate(4);

Zwraca: cześć ...

brak loga
źródło
@SarjanWebDev Ten znak specjalny pojawia się jako „.” w cmd.exe
Neal Ehardt
5

Podobny wariant z operatorem propagacji zerowej C # 6

public static string Truncate(this string value, int maxLength)
{
    return value?.Length <= maxLength ? value : value?.Substring(0, maxLength);
}

Należy pamiętać, że zasadniczo sprawdzamy, czy tutaj valuejest dwa razy zerowy.

Jamie Rees
źródło
5

Nadal nie ma metody obcinania w 2016 r. Dla ciągów C #. Ale - przy użyciu składni C # 6.0:

public static class StringExtension
{
  public static string Truncate(this string s, int max) 
  { 
    return s?.Length > max ? s.Substring(0, max) : s ?? throw new ArgumentNullException(s); 
  }
}

To działa jak urok:

"Truncate me".Truncate(8);
Result: "Truncate"
Tobias Schiele
źródło
4

Biorąc @CaffGeek i upraszczając go:

public static string Truncate(this string value, int maxLength)
    {
        return string.IsNullOrEmpty(value) ? value : value.Substring(0, Math.Min(value.Length, maxLength));
    }
Edwin Beltran
źródło
4

Kndly zauważa, że ​​obcięcie łańcucha nie oznacza po prostu cięcia samego łańcucha o określonej długości, ale należy uważać, aby nie rozdzielić słowa.

np. ciąg: jest to ciąg testowy.

Chcę to wyciąć o 11. Jeśli użyjemy dowolnej z metod podanych powyżej, wynik będzie

to jest te

Nie tego chcemy

Metoda, której używam, może również nie być tak idealna, ale może poradzić sobie z większością sytuacji

public string CutString(string source, int length)
{
        if (source== null || source.Length < length)
        {
            return source;
        }
        int nextSpace = source.LastIndexOf(" ", length);
        return string.Format("{0}...", input.Substring(0, (nextSpace > 0) ? nextSpace : length).Trim());
} 
Sen K. Mathew
źródło
4

Dlaczego nie:

string NormalizeLength(string value, int maxLength)
{
    //check String.IsNullOrEmpty(value) and act on it. 
    return value.PadRight(maxLength).Substring(0, maxLength);
}

tj. w polu zdarzeń value.Length < maxLengthodstępy do końca lub obcięcie nadmiaru.

Sri
źródło
Generujesz dwa razy więcej obiektów łańcuchowych i może generować wyjątek NullReferenceException z wywołania PadRight, jeśli wartość jest null, co jest niewłaściwe, powinien to być ArgumentNullException.
Jeremy
1
@Jeremy Nie rozumiem "może wyrzucić wyjątek NullReferenceException z wywołania PadRight, jeśli wartość jest pusta"; czy nie wspomniałem o „// sprawdź ciąg.IsNullOrEmpty (wartość) i działaj na nim”.
Sri
3

Na wypadek, gdyby nie było wystarczająco dużo odpowiedzi, oto moje :)

public static string Truncate(this string str, 
                              int totalLength, 
                              string truncationIndicator = "")
{
    if (string.IsNullOrEmpty(str) || str.Length < totalLength) 
        return str;

    return str.Substring(0, totalLength - truncationIndicator.Length) 
           + truncationIndicator;
}

używać:

"I use it like this".Truncate(5,"~")
KR
źródło
2

Ze względu na (nadmierną) złożoność dodam moją przeciążoną wersję, która zastępuje ostatnie 3 znaki wielokropkiem w odniesieniu do parametru maxLength.

public static string Truncate(this string value, int maxLength, bool replaceTruncatedCharWithEllipsis = false)
{
    if (replaceTruncatedCharWithEllipsis && maxLength <= 3)
        throw new ArgumentOutOfRangeException("maxLength",
            "maxLength should be greater than three when replacing with an ellipsis.");

    if (String.IsNullOrWhiteSpace(value)) 
        return String.Empty;

    if (replaceTruncatedCharWithEllipsis &&
        value.Length > maxLength)
    {
        return value.Substring(0, maxLength - 3) + "...";
    }

    return value.Substring(0, Math.Min(value.Length, maxLength)); 
}
SoftDev
źródło
2

Moje dwa centy o przykładowej długości 30:

  var truncatedInput = string.IsNullOrEmpty(input) ? 
      string.Empty : 
      input.Substring(0, Math.Min(input.Length, 30));
Ognyan Dimitrov
źródło
1

Wolę odpowiedź jpiersona, ale żaden z przykładów, które widzę, nie obsługuje nieprawidłowego parametru maxLength, na przykład gdy maxLength <0.

Wybierane byłyby albo obsłużyć błąd w try / catch, ustawić parametr maxLength min na 0, lub jeśli maxLength jest mniejszy niż 0, zwrócić pusty ciąg

Niezoptymalizowany kod:

public string Truncate(this string value, int maximumLength)
{
    if (string.IsNullOrEmpty(value) == true) { return value; }
    if (maximumLen < 0) { return String.Empty; }
    if (value.Length > maximumLength) { return value.Substring(0, maximumLength); }
    return value;
}
deegee
źródło
3
Zauważ, że w mojej implementacji postanowiłem nie zajmować się przypadkiem, w którym maximumLength jest mniejsze niż 0, ponieważ pomyślałem, że jedyne, co bym zrobił, to rzucić ArgumentOutOfRangeExcpetion, który zasadniczo jest dla mnie tym, co robi string.Substring ().
jpierson
1

Oto rozwiązanie vb.net, zaznacz, że instrukcja if (choć brzydka) poprawia wydajność, ponieważ nie potrzebujemy instrukcji substring, gdy łańcuch jest już mniejszy niż maxlength ... Dzięki temu, że jest rozszerzeniem łańcucha, jest łatwy w użyciu. ..

 <System.Runtime.CompilerServices.Extension()> _
    Public Function Truncate(String__1 As String, maxlength As Integer) As String
        If Not String.IsNullOrEmpty(String__1) AndAlso String__1.Length > maxlength Then
            Return String__1.Substring(0, maxlength)
        Else
            Return String__1
        End If
    End Function
Jeroen Bom
źródło
W VB.net możesz zamienić „Not String.IsNullOrEmpty (String__1)” na „String__1 <> Nic”. Jest trochę krótszy. Domyślną wartością dla ciągów jest pusty ciąg. Użycie „<> Nic” sprawdza zarówno puste, jak i puste ciągi znaków. Przetestuj to za pomocą: Truncate („”, 50) i Truncate (Nic, 50)
jrjensen
W VB możesz zrobić Left (string, maxlength)
Michael Z.
1

Wiem, że jest już mnóstwo odpowiedzi, ale potrzebowałem utrzymać nienaruszony początek i koniec łańcucha, ale skrócić go poniżej maksymalnej długości.

    public static string TruncateMiddle(string source)
    {
        if (String.IsNullOrWhiteSpace(source) || source.Length < 260) 
            return source;

        return string.Format("{0}...{1}", 
            source.Substring(0, 235),
            source.Substring(source.Length - 20));
    }

Służy to do tworzenia adresów URL programu SharePoint o maksymalnej długości 260 znaków.

Nie ustawiłem długości jako parametru, ponieważ jest to stała 260. Nie uczyniłem też pierwszej długości podłańcucha parametrem, ponieważ chcę, aby pękała w określonym punkcie. Wreszcie drugi podciąg to długość źródła - 20, ponieważ znam strukturę folderów.

Można to łatwo dostosować do konkretnych potrzeb.

Paul Haan
źródło
1

Wiem, że jest tu już mnóstwo odpowiedzi, ale jest to ta, z którą poszedłem, która obsługuje zarówno ciągi zerowe, a sytuacja, w której przekazywana długość jest ujemna:

public static string Truncate(this string s, int length)
{
    return string.IsNullOrEmpty(s) || s.Length <= length ? s 
        : length <= 0 ? string.Empty 
        : s.Substring(0, length);
}
Ed B.
źródło
1

W C # 8 można użyć nowej funkcji Ranges ...

value = value[..Math.Min(30, value.Length)];
Sunsetquest
źródło
0

Nic nie wiem o tym w .net - oto moja wersja, która dodaje „...”:

public static string truncateString(string originalString, int length) {
  if (string.IsNullOrEmpty(originalString)) {
   return originalString;
  }
  if (originalString.Length > length) {
   return originalString.Substring(0, length) + "...";
  }
  else {
   return originalString;
  }
}
Promień
źródło
2
Twoja wersja da ciągi o 3 znaki dłuższe niż żądana długość, na wypadek, gdyby zostały obcięte. Poza tym potrójne kropki mają tak naprawdę znaczenie tylko w reprezentacji, nie zapisałbym ich w takiej bazie danych, która jest przykładem użycia, jaki dał OP.
MarioDS
0

TruncateString

public static string _TruncateString(string input, int charaterlimit)
{
    int characterLimit = charaterlimit;
    string output = input;

    // Check if the string is longer than the allowed amount
    // otherwise do nothing
    if (output.Length > characterLimit && characterLimit > 0)
    {
        // cut the string down to the maximum number of characters
        output = output.Substring(0, characterLimit);
        // Check if the character right after the truncate point was a space
        // if not, we are in the middle of a word and need to remove the rest of it
        if (input.Substring(output.Length, 1) != " ")
        {
            int LastSpace = output.LastIndexOf(" ");

            // if we found a space then, cut back to that space
            if (LastSpace != -1)
            {
                output = output.Substring(0, LastSpace);
            }
        }
        // Finally, add the "..."
        output += "...";
    }
    return output;
}
Sud
źródło
2
Dlaczego poprzednią nazwę metody publicznej poprzedzasz podkreśleniem?
Michael Z.
0

Jako dodatek do omówionych powyżej możliwości chciałbym podzielić się moim rozwiązaniem. Jest to metoda rozszerzenia, która pozwala null (zwraca string.Empty), istnieje również druga metoda .Truncate () do używania jej z wielokropkiem. Uwaga, nie jest zoptymalizowana pod kątem wydajności.

public static string Truncate(this string value, int maxLength) =>
    (value ?? string.Empty).Substring(0, (value?.Length ?? 0) <= (maxLength < 0 ? 0 : maxLength) ? (value?.Length ?? 0) : (maxLength < 0 ? 0 : maxLength));
public static string Truncate(this string value, int maxLength, string ellipsis) =>
    string.Concat(value.Truncate(maxLength - (((value?.Length ?? 0) > maxLength ? ellipsis : null)?.Length ?? 0)), ((value?.Length ?? 0) > maxLength ? ellipsis : null)).Truncate(maxLength);
Raymond Osterbrink
źródło
-1
public static string Truncate( this string value, int maxLength )
    {
        if (string.IsNullOrEmpty(value)) { return value; }

        return new string(value.Take(maxLength).ToArray());// use LINQ and be happy
    }
TapiocaCom
źródło
ToArray()Wezwanie tutaj jest po prostu niepotrzebny narzut; używając np. String.Concatmożesz skonstruować ciąg znaków z wyliczalnej liczby znaków bez konieczności przechodzenia przez tablicę.
Mark Amery
-3

Obciąć ciąg

public static string TruncateText(string strText, int intLength)
{
    if (!(string.IsNullOrEmpty(strText)))
    {                                
        // split the text.
        var words = strText.Split(' ');

        // calculate the number of words
        // based on the provided characters length 
        // use an average of 7.6 chars per word.
        int wordLength = Convert.ToInt32(Math.Ceiling(intLength / 7.6));

        // if the text is shorter than the length,
        // display the text without changing it.
        if (words.Length <= wordLength)
            return strText.Trim();                

        // put together a shorter text
        // based on the number of words
        return string.Join(" ", words.Take(wordLength)) + " ...".Trim();
    }
        else
        {
            return "";
        }            
    }
VT
źródło
To nie odpowiada na pytanie PO. Po pierwsze, powinna to być funkcja członkowska (chociaż napisałeś ją jako metodę rozszerzenia). Po drugie, PO nie określa, że ​​tekst musi zostać podzielony, a słowa skrócone do ok. 7,6 znaków na słowo.
Wicher Visser
7,6 to tylko liczba. możesz wpisać dowolny inny numer. Okazało się, że jest to średnia angielska długość słowa. Znalazłem to w Google. Korzystanie z podziału jest po prostu łatwym sposobem dzielenia słów według miejsca. Nie sądzę, że chcesz wyświetlić pół słowa! Więc jeśli nie zapętlisz się, by znaleźć puste miejsce, które będzie wymagało więcej kodu, jest to prosty sposób na obcięcie łańcucha i wyświetlenie pełnych słów. Zapewni to, że łańcuch nie będzie dłuższy niż podana długość i nie będziesz łamał słów.
VT
-4

Oto kod, którego zwykle używam:

string getSubString(string value, int index, int length)
        {
            if (string.IsNullOrEmpty(value) || value.Length <= length)
            {
                return value;
            }
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            for (int i = index; i < length; i++)
            {
                sb.AppendLine(value[i].ToString());
            }
            return sb.ToString();
        }
użytkownik3390116
źródło
5
Pamiętaj, że łączenie łańcuchów z + = jest kosztowną operacją, szczególnie przy przebudowywaniu znak po znaku. Ciągi .NET są niezmienne, co oznacza, że ​​w tym przypadku nowy ciąg jest tworzony za każdym razem w pętli.
Steve Guidi,
Ciągi @ SteveGuidi nie są niezmienne, po prostu udają niezmienne. Chciałbym, żeby łańcuchy były prawdziwymi niezmiennymi prymitywami, abym mógł mieć łańcuch i łańcuch ?, ale niestety nie są to prymitywy.
Chris Marisic
Mówisz drogo, jakby koszt wydajności był znaczny, zmieniłem go na stringBuilder, ale uważam, że z + = łatwiej jest zobaczyć, co się dzieje, chciałem tylko, żeby OP łatwo zrozumiał kod.
user3390116