2010-06-01 18 views
64

Szukałem, ale zaskakująco nie mogłem znaleźć odpowiedzi.Jak mogę skrócić NSString do ustawionej długości?

Mam długi NSString, który chcę skrócić. Chcę, aby maksymalna długość wynosiła około 20 znaków. Czytałem gdzieś, że najlepszym rozwiązaniem jest użycie substringWithRange. Czy to jest najlepszy sposób na obcięcie łańcucha?

NSRange stringRange = {0,20}; 
NSString *myString = @"This is a string, it's a very long string, it's a very long string indeed"; 
NSString *shortString = [myString substringWithRange:stringRange]; 

Wydaje się nieco delikatny (ulega awarii, jeśli ciąg jest krótszy niż maksymalna długość). Nie jestem również pewien, czy jest bezpieczny dla Unicode. Czy istnieje lepszy sposób na zrobienie tego? Czy ktoś ma fajną kategorię do tego?

+6

... '-substringToIndex:'? – kennytm

+0

Powiązane, obcinanie według liczby bajtów zamiast znaków złożonych: [Obcinanie łańcucha zawierającego emoji lub znaki Unicode na granicy wyrazów lub znaków] (http://stackoverflow.com/q/15775294/603977) –

Odpowiedz

116

W rzeczywistości część dotycząca bycia "Unicode safe" była martwa, ponieważ wiele postaci łączy się w unicode, czego nie uwzględniają sugerowane odpowiedzi.

Na przykład, jeśli chcesz wpisać é. Jednym ze sposobów na to jest wpisanie "e" (0x65) + łączenie akcentu "" (0x301). Teraz, jeśli wpiszesz "café" w ten sposób i obetniesz 4 znaki, dostaniesz "cafe". Może to powodować problemy w niektórych miejscach.

Jeśli nie przejmujesz się tym, inne odpowiedzi działają dobrze. W przeciwnym razie wykonaj następujące czynności:

// define the range you're interested in 
NSRange stringRange = {0, MIN([myString length], 20)}; 

// adjust the range to include dependent chars 
stringRange = [myString rangeOfComposedCharacterSequencesForRange:stringRange]; 

// Now you can create the short string 
NSString *shortString = [myString substringWithRange:stringRange]; 

Należy zauważyć, że w ten sposób zakres może być dłuższy niż początkowa długość zakresu. W powyższym przykładzie kawiarni twój zasięg rozszerzy się do długości 5, nawet jeśli nadal masz 4 "glify". Jeśli absolutnie potrzebujesz mieć długość mniejszą niż wskazana, musisz to sprawdzić.

+0

Dzięki za odpowiedź. Czy japoński kanji ma wpływ na łączony problem z akcentem, o którym wspomniałeś? Od używania twojego rozwiązania wydaje się dobrze współpracować z kanji. –

+0

Obawiam się, że nie jestem obeznany ze znakami kanji, ale przypuszczam, że wszystkie one są pojedynczymi znakami (Unicode 0x4E00 do 0x9FAF), więc nie powinny tego potrzebować. Ale znowu, nie jestem pewien ... – mohsenr

+0

@mosensen Właśnie testowałem z "kawiarnią" PRZED i PO UCHNIĘCIE (używając rozwiązania OP), oba dają długość 4. Myślę, że iOS uważa "é" za POJEDYNCZY charakter !!! – onmyway133

3

Przydałoby potrójny operacji:

NSString *shortString = (stringRange.length <= [myString length]) ? myString : [myString substringWithRange:stringRange]; 

albo większą kontrolę nad efektem końcowym:

if (stringRange.length > [myString length]) 
    // throw exception, ignore error, or set shortString to myString 
else 
    shortString = [myString substringWithRange:stringRange]; 
+0

Przyjemna jedna linijka, dzięki Alex. –

6

To wydaje się trochę delikatne (awarie, jeśli ciąg jest krótszy niż maksymalny długość)

To dlaczego nie naprawić tej części?

NSRange stringRange = {0, MIN([myString length], 20)}; 
+0

Ładne rozwiązanie, dzięki. –

0

Wszystkie operacje NSString są bezpieczne dla Unicode, ponieważ NSString jest wewnętrznie wewnętrzną tablicą unichar. Nawet jeśli ciąg jest w innym kodowaniu, jest konwertowany na określone kodowanie, gdy jest wyświetlany.

+4

Właściwie nie, to nie jest dokładnie bezpieczne dla Unicode, ponieważ niektóre znaki Unicode używają więcej niż jednego unichar. Chcesz uniknąć dzielenia ciągu w środku takiej sekwencji. Stąd potrzeba takich metod jak 'rangeOfComposedCharacterSequenceAtIndex:'. – JWWalker

11

Krótszy rozwiązaniem jest:

NSString *shortString = ([myString length]>MINLENGTH ? [myString substringToIndex:MINLENGTH] : myString); 
2
//Short the string if string more than 45 chars 
    if([self.tableCellNames[indexPath.section] length] > 40) { 

     // define the range you're interested in 
     NSRange stringRange = {0, MIN([self.tableCellNames[indexPath.section] length], 40)}; 

     // adjust the range to include dependent chars 
     stringRange = [self.tableCellNames[indexPath.section] 
         rangeOfComposedCharacterSequencesForRange:stringRange]; 

     // Now you can create the short string 
     NSString *shortStringTitle = [self.tableCellNames[indexPath.section] substringWithRange:stringRange]; 

     shortStringTitle = [shortStringTitle stringByAppendingString:@"..."]; 

     titleLabel.text = shortStringTitle; 

    } else { 

     titleLabel.text = self.tableCellNames[indexPath.section]; 
    } 

// VKJ

12

Ponieważ odpowiedź ta nie jest faktycznie na tej liście, to najprostszy i najbardziej sensowne jedno-liner:

NSString *myString = @"This is a string, it's a very long string, it's a very long string indeed"; 
myString = (myString.length > 20) ? [myString substringToIndex:20] : myString; 
+0

Świetnie! Ponieważ nie mogę edytować błędu literowego jednego znaku, umieszczę go tutaj: [myString subStringToIndex: 20]; powinien być [myString substringToIndex: 20]; – user23127

+0

Dobry połów - naprawiony! – brandonscript

+0

Wyrzucam wyjątek, jeśli "mójString.lenght" jest wyższy niż "20". Musisz przetestować go przed –

0

Jeśli chcesz obciąć z końcowego użytku:

[fileName substringToIndex:anyNumber]; 

Jeśli chcesz obciąć od początku:

[fileName substringFromIndex:anyNumber]; 
1

Najprostszym i ładne rozwiązanie (z "..." na końcu tekstu):

NSString *newText = [oldText length] > intTextLimit ? [[oldText substringToIndex:intTextLimit] stringByAppendingString:@"..."] : oldText; 
1

Swift 4

Happy Coding.