Згорнути послідовності пробілу в один символ і обрізати рядок


122

Розглянемо наступний приклад:

"    Hello      this  is a   long       string!   "

Я хочу перетворити це на:

"Hello this is a long string!"

Відповіді:


125

OS X 10.7+ та iOS 3.2+

Використовуйте нативний розчин regexp, наданий hfossli.

Інакше

Або скористайтеся улюбленою бібліотекою regexp або скористайтеся наступним рішенням для какао:

NSString *theString = @"    Hello      this  is a   long       string!   ";

NSCharacterSet *whitespaces = [NSCharacterSet whitespaceCharacterSet];
NSPredicate *noEmptyStrings = [NSPredicate predicateWithFormat:@"SELF != ''"];

NSArray *parts = [theString componentsSeparatedByCharactersInSet:whitespaces];
NSArray *filteredArray = [parts filteredArrayUsingPredicate:noEmptyStrings];
theString = [filteredArray componentsJoinedByString:@" "];

4
Мені було б цікаво порівняти ефективність цього варіанту із заміною регулярного вибору з обробкою для видалення кінців. З одного боку, у вас є регекс для вирішення. З іншого - у вас є присудок. Або необхідна внутрішня обробка відповідних виразів.
lilbyrdie

@lilbyrdie: Це залежить від рядка, на який я думаю, скільки пробілів є. Моє рішення є досить повільним, оскільки створює новий об'єкт для кожної підрядки і надсилає виклики методів до кожної з них.
Георг Шоллі

2
Тонка відповідь, висловлена ​​як така, але я оскаржую ваше визначення "легко". З повагою, колишній хлопець Python зараз в ObjC-land ;-)
JK Laiho

2
Ви змусили мене сміятися з "не використовуйте складних рішень, якщо є легке". Отже, найпростіший - це [toBeTrimmed stringByReplacingOccurrencesOfString: @ "" withString: @ ""] ні? Я все ще підтримую вашу відповідь, але це, безумовно, найпростіше
Маріо Карвальо

2
@ MárioCarvalho Питання задає питання, як видалити зайвий пробіл, не все.
swilliams

52

Тут допоможуть Regex і NSCharacterSet. Це рішення обробляє провідні та кінцеві пробіли, а також кілька пробілів.

NSString *original = @"    Hello      this  is a   long       string!   ";

NSString *squashed = [original stringByReplacingOccurrencesOfString:@"[ ]+"
                                                         withString:@" "
                                                            options:NSRegularExpressionSearch
                                                              range:NSMakeRange(0, original.length)];

NSString *final = [squashed stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

Ведення журналів finalдає

"Hello this is a long string!"

Можливі альтернативні схеми регулярного вираження:

  • Замініть лише місце: [ ]+
  • Замініть простір та вкладки: [ \\t]+
  • Замініть простір, вкладки та нові рядки: \\s+

Виконання

Простота розширення, продуктивності, рядків номера коду та кількість створених об'єктів робить це рішення відповідним.


3
hfossli's - це найелегантніша відповідь у моїй книзі. Плюс щойно я дізнався, що ви можете використовувати регулярні вирази в stringByReplacingOccurrencesOfString:. Не можу повірити, що я цього не знав.
davidf2281

1
Дивовижно. Працював як шарм
Кушаль Ашок

41

Насправді для цього є дуже просте рішення:

NSString *string = @" spaces in front and at the end ";
NSString *trimmedString = [string stringByTrimmingCharactersInSet:
                                  [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(@"%@", trimmedString)

( Джерело )


29
Я думаю, що це позбудеться лише провідних та кінцевих просторів та усуне їх усі. це не буде мати справу з "привіт
фу

2
d * mn закінчення рядка та автоматичний формат ... він не має стосунку до "hello______foo" (припустимо _ -> "", оскільки форматування коментарів важке)
Brian Postow

32
Чому ви голосуєте за та відповіді, що не забезпечує вирішення питання? stringByTrimmingCharactersInSet не аналізує і розмір рядка, а лише ребра. Відповідь Георга Шоллі - ідеальна.
Лукаш

3
Не було точно відповіді на запитання, але воно мені точно допомогло. Дякую
daveMac

1
Відмінний код для одночасного видалення провідного та нижнього простору
користувач523234

13

З регулярним виразом, але без необхідності жодних зовнішніх рамок:

NSString *theString = @"    Hello      this  is a   long       string!   ";

theString = [theString stringByReplacingOccurrencesOfString:@" +" withString:@" "
                       options:NSRegularExpressionSearch
                       range:NSMakeRange(0, theString.length)];

Потім вам також потрібно буде обрізати результат, інакше ви будете залиті пробілом. Це, мабуть, найпростіша відповідь.
lilbyrdie

2
Документація для NSRegularExpressionSearchговорить, що вона працює лише з rangeOfString:...методами
user102008

9

Рішення в одну лінію:

NSString *whitespaceString = @" String with whitespaces ";

NSString *trimmedString = [whitespaceString
        stringByReplacingOccurrencesOfString:@" " withString:@""];

2
Допомогли мені :). Дякую за це!
thedom

5
Хоча це корисно, воно видаляє весь пробіл. ОП в основному бажає ущільнення пробілів, наприклад обрізки з подальшим зменшенням послідовного пробілу до одного простору пробілів.
lilbyrdie

Ще одна примітка, це рішення не стосується вкладок, нових рядків або символів пробілу, окрім пробілів.
fwielstra

2
Це не відповідає ОП, але натомість видаляє всі пробіли в рядку, тож ви закінчуєте @ "Stringwithwhitespaces"
charles

6

Це має зробити це ...

NSString *s = @"this is    a  string    with lots  of     white space";
NSArray *comps = [s componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

NSMutableArray *words = [NSMutableArray array];
for(NSString *comp in comps) {
  if([comp length] > 1)) {
    [words addObject:comp];
  }
}

NSString *result = [words componentsJoinedByString:@" "];

1
Це насправді працює з рядком 'a'? Це довжина 1, наскільки я бачу, це рішення відфільтрує всі розділені слова розміром 0 і 1.
fwielstra

Так, саме такої відповіді я очікував. Дякуємо +1
понеділок

4

Ще один варіант для регулярного вибору - RegexKitLite , який дуже легко вбудувати в проект iPhone:

[theString stringByReplacingOccurencesOfRegex:@" +" withString:@" "];

3

Спробуйте це

NSString *theString = @"    Hello      this  is a   long       string!   ";

while ([theString rangeOfString:@"  "].location != NSNotFound) {
    theString = [theString stringByReplacingOccurrencesOfString:@"  " withString:@" "];
}

3

Ось фрагмент із NSStringрозширення, де "self"є NSStringекземпляр. Він може бути використаний для згортання суміжних пробілів в єдиний простір шляхом передачі [NSCharacterSet whitespaceAndNewlineCharacterSet]та ' 'двох аргументів.

- (NSString *) stringCollapsingCharacterSet: (NSCharacterSet *) characterSet toCharacter: (unichar) ch {
int fullLength = [self length];
int length = 0;
unichar *newString = malloc(sizeof(unichar) * (fullLength + 1));

BOOL isInCharset = NO;
for (int i = 0; i < fullLength; i++) {
    unichar thisChar = [self characterAtIndex: i];

    if ([characterSet characterIsMember: thisChar]) {
        isInCharset = YES;
    }
    else {
        if (isInCharset) {
            newString[length++] = ch;
        }

        newString[length++] = thisChar;
        isInCharset = NO;
    }
}

newString[length] = '\0';

NSString *result = [NSString stringWithCharacters: newString length: length];

free(newString);

return result;
}

-1

Альтернативне рішення: придбайте собі копію OgreKit (бібліотеки регулярних виразів какао).

  • OgreKit (японська веб-сторінка - код англійською мовою)
  • OgreKit (автопереклад Google):

Вся функція тоді:

NSString *theStringTrimmed =
   [theString stringByTrimmingCharactersInSet:
        [NSCharacterSet whitespaceAndNewlineCharacterSet]];
OGRegularExpression  *regex =
    [OGRegularExpression regularExpressionWithString:@"\s+"];
return [regex replaceAllMatchesInString:theStringTrimmed withString:@" "]);

Короткий і милий.

Якщо ви шукаєте найшвидше рішення, ретельно побудована серія інструкцій з використанням NSScanner, ймовірно, буде найкраще працювати, але це буде потрібно лише в тому випадку, якщо ви плануєте обробляти величезні (багато мегабайт) текстові блоки.


Чи є причина використовувати OgreKit замість RegExKitLite? regexkit.sourceforge.net Він має дуже схожий виклик заміниOccurrencesOfRegex і працює над існуючими бібліотеками RegEX (не впевнений, що Ogre - це цілий двигун RegEX чи що)
Kendall Helmstetter Gelner

Я впевнений, що обоє будуть працювати. Я не використовував regexkit, але це гарна пропозиція зробити. Люди повинні вибирати на основі бібліотек, що лежать в основі: pcre-сумісний pcre (RegExKitLite) та сумісний з Ruby Oniguruma (OgreKit).
Метт Галлахер

-1

згідно з @Mathieu Годарт - найкраща відповідь, але якийсь рядок відсутній, усі відповіді просто зменшують пробіл між словами, але коли, якщо у вас є вкладки або є вкладка в просторі, наприклад: "це текст \ t і \ tTab між, так далі "у трьох рядкових кодах ми будемо: рядок, який ми хочемо зменшити пробілами

NSString * str_aLine = @"    this is text \t , and\tTab between      , so on    ";
// replace tabs to space
str_aLine = [str_aLine stringByReplacingOccurrencesOfString:@"\t" withString:@" "];
// reduce spaces to one space
str_aLine = [str_aLine stringByReplacingOccurrencesOfString:@" +" withString:@" "
                                                    options:NSRegularExpressionSearch
                                                      range:NSMakeRange(0, str_aLine.length)];
// trim begin and end from white spaces
str_aLine = [str_aLine stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

результат є

"this is text , and Tab between , so on"

без заміни вкладки результат буде:

"this is text    , and  Tab between , so on"

-1

Ви також можете використовувати простий аргумент while. У нас немає ніякої магії RegEx, тому, можливо, її легше зрозуміти та змінити в майбутньому:

while([yourNSStringObject replaceOccurrencesOfString:@"  "
                         withString:@" "
                         options:0
                         range:NSMakeRange(0, [yourNSStringObject length])] > 0);

1
Не відповідає на запитання :) Це не вилучає пробіли пробігу та відставання.
hfossli

-1

Наступні два регулярні вирази діятимуть залежно від вимог

  1. @ "+" для відповідності пробілів та вкладок
  2. @ "\\ s {2,}" для відповідності пробілів, вкладок та розривів рядків

Потім застосуйте метод екземпляра nsstring, stringByReplacingOccurrencesOfString:withString:options:range:щоб замінити їх єдиним пробілом.

напр

[string stringByReplacingOccurrencesOfString:regex withString:@" " options:NSRegularExpressionSearch range:NSMakeRange(0, [string length])];

Примітка. Я не використовував бібліотеку "RegexKitLite" для вищезазначених функцій для iOS 5.x і вище.


Це рішення не видаляє пробіли проміжних та кінцевих пробілів, як цього вимагає ОП.
hfossli

Провідні / кінцеві пробіли @hfossli можна видалити, натиснувши безпосередньо рядок NSStringByTrimmingCharactersInSet: метод з новим / білим набором символів. Вищевикладене рішення полягало у видаленні зайвих просторів незалежно від їх розташування.
apalvai
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.