Свернуть последовательности пробелов в один символ и обрезать строку

122

Рассмотрим следующий пример:

"    Hello      this  is a   long       string!   "

Я хочу преобразовать это в:

"Hello this is a long string!"
hfossli
источник

Ответы:

125

OS X 10.7+ и iOS 3.2+

Используйте собственное решение для регулярных выражений, предоставленное hfossli.

В противном случае

Либо используйте свою любимую библиотеку регулярных выражений, либо используйте следующее решение для Cocoa:

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 01
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+

Краткое описание производительности

Простота расширения, производительность, количество строк кода и количество созданных объектов делают это решение подходящим.

hfossli
источник
3
hfossli - самый элегантный ответ в моей книге. Кроме того, я только что узнал, что вы можете использовать регулярные выражения в stringByReplacingOccurrencesOfString:. Не могу поверить, что не знал этого.
davidf2281
1
Потрясающие. Сработал как шарм
Кушал Ашок
41

На самом деле, есть очень простое решение:

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

( Источник )

arikfr
источник
29
Я думаю, что это устранит только начальные и конечные пробелы и устранит их все. он не будет иметь дело с "привет
фу
2
d * mn окончания строк и автоформат ... он не имеет отношения к "hello______foo" (предположим, _ -> "", потому что форматировать комментарии сложно)
Брайан Постоу
32
Почему вы голосуете за и ответы, которые не дают решения на вопрос? stringByTrimmingCharactersInSet не анализирует ни сторону строки, а только края. Ответ Георга Шолли - идеальный.
Lukasz
3
Это был не совсем ответ на вопрос, но мне это помогло. Спасибо
daveMac
1
Отличный код для одновременного удаления начального и конечного пробелов.
user523234
13

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

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

theString = [theString stringByReplacingOccurrencesOfString:@" +" withString:@" "
                       options:NSRegularExpressionSearch
                       range:NSMakeRange(0, theString.length)];
MonsieurDart
источник
Вам также все равно нужно будет обрезать результат, иначе вы будете заполнены пробелами. Но это, наверное, самый простой ответ.
lilbyrdie
2
в документации NSRegularExpressionSearchуказано, что он работает только с rangeOfString:...методами
user102008 05
9

Однострочное решение:

NSString *whitespaceString = @" String with whitespaces ";

NSString *trimmedString = [whitespaceString
        stringByReplacingOccurrencesOfString:@" " withString:@""];
TwoBeerGuy
источник
2
Выручил меня :). Спасибо за это!
thedom
5
Хотя это полезно, оно удаляет все пробелы. OP в основном хочет уплотнения пробелов, например обрезки с последующим сокращением последовательных пробелов до одного пробела.
lilbyrdie
Еще одно замечание: это решение не имеет дело с табуляциями, новой строкой или пробельными символами, кроме пробелов.
fwielstra
2
Это не отвечает на OP, но вместо этого удаляет все пробелы в строке, так что вы получаете @ "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
Действительно ли это работает со строкой «а»? У него длина 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:@" "];
}
sinh99
источник
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;
}
dmercredi
источник
-1

Альтернативное решение: получите копию OgreKit (библиотека регулярных выражений Какао).

Тогда вся функция:

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

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

Если вы ищете самое быстрое решение, NSScannerвероятно, лучше всего подойдет тщательно продуманная серия инструкций, но это будет необходимо только в том случае, если вы планируете обрабатывать огромные (многие мегабайты) блоки текста.

Мэтт Галлахер
источник
Есть ли причина использовать OgreKit вместо RegExKitLite? regexkit.sourceforge.net Он имеет очень похожий вызов replaceOccurrencesOfRegex и работает поверх существующих библиотек RegEX (не уверен, является ли Ogre целым движком RegEX или чем-то еще)
Кендалл Хельмстеттер Гельнер
Я уверен, что оба будут работать. Я не использовал regexkit, но это хорошее предложение. Люди должны выбирать на основе базовых библиотек: PERL-совместимый pcre (RegExKitLite) и Ruby-совместимый Oniguruma (OgreKit).
Мэтт Галлахер,
-1

в соответствии с @Mathieu Godart - лучший ответ, но какая-то строка отсутствует, все ответы просто уменьшают пространство между словами, но если есть вкладки или вкладка на месте, например: "это текст \ 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"
Kosar
источник
-1

Вы также можете использовать простой аргумент while. В нем нет магии RegEx, поэтому, возможно, его будет легче понять и изменить в будущем:

while([yourNSStringObject replaceOccurrencesOfString:@"  "
                         withString:@" "
                         options:0
                         range:NSMakeRange(0, [yourNSStringObject length])] > 0);
Свен-Штеффен Арндт
источник
1
Не отвечает на вопрос :) Не удаляет начальные и конечные пробелы.
hfossli 05
-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 и выше.

apalvai
источник
Это решение не удаляет начальные и конечные пробелы, как требует OP.
hfossli 03
@hfossli начальные / конечные пробелы могут быть удалены прямым вызовом метода NSString stringByTrimmingCharactersInSet: с новым / белым набором символов строки. Вышеупомянутое решение заключалось в удалении избыточных пространств независимо от их местоположения.
apalvai