Recolher sequências de espaço em branco em um único caractere e aparar cadeia

122

Considere o seguinte exemplo:

"    Hello      this  is a   long       string!   "

Eu quero converter isso para:

"Hello this is a long string!"
hfossli
fonte

Respostas:

125

OS X 10.7+ e iOS 3.2+

Use a solução regexp nativa fornecida pelo hfossli.

De outra forma

Use sua biblioteca regexp favorita ou use a seguinte solução nativa do cacau:

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:@" "];
Georg Schölly
fonte
4
Gostaria de ter uma comparação de desempenho disso com uma substituição de regex com uma guarnição para remover as extremidades. Por um lado, você tem um regex para lidar. Por outro, você tem um predicado. Ou requer processamento interno das respectivas expressões.
lilbyrdie
@ilbyrdie: Depende da string, acho, quantos espaços em branco existem. Minha solução é bastante lenta, porque cria um novo objeto para cada substring e envia chamadas de método para cada uma delas.
Georg Schölly
2
Ótima resposta, votada como tal, mas eu desafio sua definição de "fácil". Atenciosamente, ex-cara Python agora em ObjC-terra ;-)
JK Laiho
2
Você me fez rir com 'não use soluções complexas se houver uma fácil'. Portanto, o mais fácil é [toBeTrimmed stringByReplacingOccurrencesOfString: @ "" withString: @ ""] não? Eu ainda upvote sua resposta, mas é definitivamente o mais fácil
Mário Carvalho
2
@ MárioCarvalho A pergunta é como remover o excesso de espaço em branco, não todo.
211113
52

O Regex e o NSCharacterSet estão aqui para ajudá-lo. Essa solução apara os espaços em branco iniciais e finais, bem como vários espaços em branco.

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]];

O registro finalfornece

"Hello this is a long string!"

Possíveis padrões alternativos de regex:

  • Substitua apenas espaço: [ ]+
  • Substitua o espaço e as guias: [ \\t]+
  • Substitua espaço, guias e novas linhas: \\s+

Resumo do desempenho

A facilidade de extensão, desempenho, número de linhas de código e o número de objetos criados tornam essa solução apropriada.

hfossli
fonte
3
hfossli é a resposta mais elegante do meu livro. Além disso, aprendi que você pode usar expressões regulares no stringByReplacingOccurrencesOfString:. Não posso acreditar que não sabia disso.
Davidf2281
1
Impressionante. Trabalhou como um encanto
Kushal Ashok
41

Na verdade, há uma solução muito simples para isso:

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

( Fonte )

arikfr
fonte
29
Eu acho que isso eliminará apenas os espaços iniciais e finais, e eliminará todos eles. ele não vai lidar com "foo Olá"
Brian Postow
2
d * final de linha mn e auto-formato ... não lidar com "hello______foo" (assumir _ -> "", porque a formatação de comentários é difícil)
Brian Postow
32
Por que vocês votam e respostas que não fornecem solução para a pergunta? stringByTrimmingCharactersInSet não analisa o lado da string, mas apenas arestas. Resposta de Georg Sholly é a perfeita.
Lukasz
3
Não era exatamente uma resposta para a pergunta, mas com certeza me ajudou. Graças
daveMac
1
Código excelente para remover espaço inicial e final ao mesmo tempo.
user523234
13

Com uma regex, mas sem a necessidade de qualquer estrutura externa:

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

theString = [theString stringByReplacingOccurrencesOfString:@" +" withString:@" "
                       options:NSRegularExpressionSearch
                       range:NSMakeRange(0, theString.length)];
MonsieurDart
fonte
Você também precisará cortar o resultado, ou será preenchido com espaço em branco. Esta é provavelmente a resposta mais simples, no entanto.
lilbyrdie
2
a documentação NSRegularExpressionSearchdiz que ele só funciona com o rangeOfString:...métodos
user102008
9

Uma solução de uma linha:

NSString *whitespaceString = @" String with whitespaces ";

NSString *trimmedString = [whitespaceString
        stringByReplacingOccurrencesOfString:@" " withString:@""];
TwoBeerGuy
fonte
2
Me ajudou :). Obrigado por isso!
TheDom
5
Embora isso seja útil, ele remove todos os espaços em branco. O OP basicamente deseja compactação de espaço em branco, por exemplo, um ajuste seguido pela redução do espaço em branco consecutivo em um único espaço em branco.
lilbyrdie
Outra observação: esta solução não lida com tabulações, novas linhas ou caracteres de espaço em branco que não sejam espaços.
fwielstra
2
Isso não responde à OP, mas remove todos os espaços na string, então você acaba com @ "Stringwithwhitespaces"
charles
6

Isso deve servir...

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:@" "];
Barry Wark
fonte
1
Isso realmente funciona com a string 'a'? É de comprimento 1, tanto quanto eu posso ver, esta solução irá filtrar todas as palavras dividir com tamanho 0 e 1.
fwielstra
Sim, essa é a resposta que eu estava esperando. Obrigado +1
पवन
4

Outra opção para o regex é o RegexKitLite , que é muito fácil de incorporar em um projeto do iPhone:

[theString stringByReplacingOccurencesOfRegex:@" +" withString:@" "];
Daniel Dickison
fonte
3

Experimente isto

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

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

Aqui está um trecho de uma NSStringextensão, onde "self"está a NSStringinstância. Ele pode ser usado para recolher espaços em branco contíguos em um único espaço, passando para [NSCharacterSet whitespaceAndNewlineCharacterSet]e ' 'para os dois argumentos.

- (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
fonte
-1

Solução alternativa: obtenha uma cópia do OgreKit (a biblioteca de expressões regulares do Cocoa).

Toda a função é então:

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

Curto e grosso.

Se você procura a solução mais rápida, uma série de instruções cuidadosamente construída NSScannerprovavelmente funcionaria melhor, mas isso só seria necessário se você planeja processar grandes blocos de texto (muitos megabytes).

Matt Gallagher
fonte
Existe um motivo para usar o OgreKit em vez do RegExKitLite? regexkit.sourceforge.net Tem uma chamada replaceOccurrencesOfRegex muito semelhante, e trabalha em cima das bibliotecas REGEX existentes (não sei se Ogre é um motor de todo regex ou o que)
Kendall Helmstetter Gelner
Tenho certeza que ambos irão funcionar. Eu não usei o regexkit, mas é uma boa sugestão a fazer. As pessoas devem escolher com base nas bibliotecas subjacentes: o PCRE compatível com PERL (RegExKitLite) e o Oniguruma compatível com Ruby (OgreKit).
Matt Gallagher
-1

de acordo comathieu Godart, é a melhor resposta, mas falta uma linha, todas as respostas reduzem o espaço entre as palavras, mas quando se têm guias ou têm espaço no lugar, é assim: "este é o texto \ t e \ tTab entre, assim por diante "no código de três linhas, vamos: a string que queremos reduzir os espaços em branco

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]];

o resultado é

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

sem substituir a guia, o resultado será:

"this is text    , and  Tab between , so on"
Kosar
fonte
-1

Você também pode usar um argumento while simples. Não há mágica RegEx lá, então talvez seja mais fácil entender e alterar no futuro:

while([yourNSStringObject replaceOccurrencesOfString:@"  "
                         withString:@" "
                         options:0
                         range:NSMakeRange(0, [yourNSStringObject length])] > 0);
Sven-Steffen Arndt
fonte
1
Não responde à pergunta :) Não remove os espaços em branco iniciais e finais.
Hfossli
-1

Seguir duas expressões regulares funcionaria dependendo dos requisitos

  1. @ "+" para combinar espaços em branco e guias
  2. @ "\\ s {2,}" para combinar espaços em branco, tabulações e quebras de linha

Em seguida, aplique o método de instância do nsstring stringByReplacingOccurrencesOfString:withString:options:range:para substituí-los por um único espaço em branco.

por exemplo

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

Nota: Eu não usei a biblioteca 'RegexKitLite' para a funcionalidade acima para iOS 5.xe acima.

apalvai
fonte
Essa solução não remove os espaços em branco iniciais e finais, conforme solicitado pelo OP.
Hfossli
Os espaços à esquerda / à esquerda do @hfossli podem ser removidos chamando diretamente o método stringByTrimmingCharactersInSet: do NSString com o novo conjunto de caracteres de linha branca /. A solução acima foi remover os espaços redundantes independentemente de sua localização.
apalvai