Supposons que ceci soit la chaîne:
The fox jumped over the log.
Il en résulterait:
The fox jumped over the log.
Quel est le plus simple, une ou deux doublures pouvant le faire? Sans se séparer et entrer dans les listes ...
>>> import re
>>> re.sub(' +', ' ', 'The quick brown fox')
'The quick brown fox'
foo est votre ficelle:
" ".join(foo.split())
Soyez averti si cela supprime "tous les caractères d'espacement (espace, tabulation, nouvelle ligne, retour, saut de page)". (Merci à hhsaffar , voir les commentaires) ie "this is \t a test\n"
finira par devenir "this is a test"
import re
s = "The fox jumped over the log."
re.sub("\s\s+" , " ", s)
ou
re.sub("\s\s+", " ", s)
puisque l'espace avant la virgule est répertorié comme un bête de bête dans PEP8, comme indiqué par orignal dans les commentaires.
En utilisant des expressions rationnelles avec "\ s" et en effectuant une simple chaîne, string.split () va aussi supprimer les autres espaces, comme les nouvelles lignes, les retours à la ligne, les tabulations. À moins que cela ne soit souhaité, pour uniquement faire plusieurs espaces, je présente ces exemples.
EDIT: Comme d'habitude, j'ai dormi là-dessus et, en plus de corriger une faute de frappe sur les derniers résultats (v3.3.3 @ 64 bits, pas 32 bits), Une évidence me frappe: la chaîne de test était plutôt triviale.
J'ai donc ... 11 paragraphes, 1000 mots, 6665 octets de Lorem Ipsum pour obtenir des tests de temps plus réalistes. J'ai ensuite ajouté des espaces supplémentaires de longueur aléatoire:
original_string = ''.join(Word + (' ' * random.randint(1, 10)) for Word in lorem_ipsum.split(' '))
J'ai également corrigé la "bonne join
"; si on s'en soucie, one-liner fera essentiellement une bande d'espaces de début/fin, cette version corrigée conserve un espace de début/fin (mais seulement UN ;-). (J'ai trouvé cela parce que le lorem_ipsum
à espacement aléatoire avait des espaces supplémentaires à la fin et qu'il échouait donc la assert
.)
# setup = '''
import re
def while_replace(string):
while ' ' in string:
string = string.replace(' ', ' ')
return string
def re_replace(string):
return re.sub(r' {2,}' , ' ', string)
def proper_join(string):
split_string = string.split(' ')
# To account for leading/trailing spaces that would simply be removed
beg = ' ' if not split_string[ 0] else ''
end = ' ' if not split_string[-1] else ''
# versus simply ' '.join(item for item in string.split(' ') if item)
return beg + ' '.join(item for item in split_string if item) + end
original_string = """Lorem ipsum ... no, really, it kept going... malesuada enim feugiat. Integer imperdiet erat."""
assert while_replace(original_string) == re_replace(original_string) == proper_join(original_string)
#'''
# while_replace_test
new_string = original_string[:]
new_string = while_replace(new_string)
assert new_string != original_string
# re_replace_test
new_string = original_string[:]
new_string = re_replace(new_string)
assert new_string != original_string
# proper_join_test
new_string = original_string[:]
new_string = proper_join(new_string)
assert new_string != original_string
REMARQUE: La "version N'oubliez pas que les instances while
" a fait une copie du original_string
. Comme je le crois, une fois modifiée lors de la première exécution, les exécutions successives seraient plus rapides (ne serait-ce que de peu). Comme cela ajoute du temps, j'ai ajouté cette copie de chaîne aux deux autres pour que les temps ne montrent la différence que dans la logique.stmt
sur timeit
ne seront exécutées qu'une seule fois ; De la même manière que j’ai fait cela, la boucle while
a fonctionné sur la même étiquette, original_string
, de sorte que lors de la deuxième exécution, il n’y aurait rien à faire. La configuration actuelle, appeler une fonction, utiliser deux étiquettes différentes, n’est pas un problème. J'ai ajouté des instructions assert
à tous les travailleurs pour vérifier que nous modifions quelque chose à chaque itération (pour ceux qui peuvent être douteux). Par exemple, changez ceci et ça casse:
# while_replace_test
new_string = original_string[:]
new_string = while_replace(new_string)
assert new_string != original_string # will break the 2nd iteration
while ' ' in original_string:
original_string = original_string.replace(' ', ' ')
Tests run on a laptop with an i5 processor running Windows 7 (64-bit).
timeit.Timer(stmt = test, setup = setup).repeat(7, 1000)
test_string = 'The fox jumped over\n\t the log.' # trivial
Python 2.7.3, 32-bit, Windows
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test | 0.001066 | 0.001260 | 0.001128 | 0.001092
re_replace_test | 0.003074 | 0.003941 | 0.003357 | 0.003349
proper_join_test | 0.002783 | 0.004829 | 0.003554 | 0.003035
Python 2.7.3, 64-bit, Windows
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test | 0.001025 | 0.001079 | 0.001052 | 0.001051
re_replace_test | 0.003213 | 0.004512 | 0.003656 | 0.003504
proper_join_test | 0.002760 | 0.006361 | 0.004626 | 0.004600
Python 3.2.3, 32-bit, Windows
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test | 0.001350 | 0.002302 | 0.001639 | 0.001357
re_replace_test | 0.006797 | 0.008107 | 0.007319 | 0.007440
proper_join_test | 0.002863 | 0.003356 | 0.003026 | 0.002975
Python 3.3.3, 64-bit, Windows
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test | 0.001444 | 0.001490 | 0.001460 | 0.001459
re_replace_test | 0.011771 | 0.012598 | 0.012082 | 0.011910
proper_join_test | 0.003741 | 0.005933 | 0.004341 | 0.004009
test_string = lorem_ipsum
# Thanks to http://www.lipsum.com/
# "Generated 11 paragraphs, 1000 words, 6665 bytes of Lorem Ipsum"
Python 2.7.3, 32-bit
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test | 0.342602 | 0.387803 | 0.359319 | 0.356284
re_replace_test | 0.337571 | 0.359821 | 0.348876 | 0.348006
proper_join_test | 0.381654 | 0.395349 | 0.388304 | 0.388193
Python 2.7.3, 64-bit
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test | 0.227471 | 0.268340 | 0.240884 | 0.236776
re_replace_test | 0.301516 | 0.325730 | 0.308626 | 0.307852
proper_join_test | 0.358766 | 0.383736 | 0.370958 | 0.371866
Python 3.2.3, 32-bit
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test | 0.438480 | 0.463380 | 0.447953 | 0.446646
re_replace_test | 0.463729 | 0.490947 | 0.472496 | 0.468778
proper_join_test | 0.397022 | 0.427817 | 0.406612 | 0.402053
Python 3.3.3, 64-bit
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test | 0.284495 | 0.294025 | 0.288735 | 0.289153
re_replace_test | 0.501351 | 0.525673 | 0.511347 | 0.508467
proper_join_test | 0.422011 | 0.448736 | 0.436196 | 0.440318
Pour la chaîne triviale, il semblerait que la boucle while soit la plus rapide, suivie de la division/jointure de chaînes Pythonic et de la regex tirant vers le haut.
Pour les chaînes non triviales, il semble y avoir un peu plus à considérer. 32 bits 2.7? C'est regex à la rescousse! 2.7 64 bits? Une boucle while
est préférable, par une marge décente. 32 bits 3.2, allez avec la "bonne" join
. 64 bits 3.3, optez pour une boucle while
. Encore.
Au final, on peut améliorer les performances si/où/quand cela est nécessaire, mais il est toujours préférable de rappeler le mantra :
IANAL, YMMV, Caveat Emptor!
Je suis d'accord avec le commentaire de Paul McGuire ci-dessus. Pour moi,
' '.join(the_string.split())
est nettement préférable à sortir une regex.
Mes mesures (Linux, Python 2.5) montrent que le split-then-join est presque 5 fois plus rapide que de faire "re.sub (...)", et toujours 3 fois plus rapidement si vous précompilez la regex une fois et effectuez l'opération plusieurs fois. Et il est de toute façon plus facile de comprendre - beaucoup plus Pythonic.
Semblable aux solutions précédentes, mais plus spécifique: remplacez deux espaces ou plus par un:
>>> import re
>>> s = "The fox jumped over the log."
>>> re.sub('\s{2,}', ' ', s)
'The fox jumped over the log.'
Une simple soultion
>>> import re
>>> s="The fox jumped over the log."
>>> print re.sub('\s+',' ', s)
The fox jumped over the log.
Vous pouvez également utiliser la technique de fractionnement de chaîne dans un fichier de données Pandas sans avoir besoin d'utiliser .apply (..), ce qui est utile si vous devez exécuter l'opération rapidement sur un grand nombre de chaînes. La voici sur une seule ligne:
df['message'] = (df['message'].str.split()).str.join(' ')
import re
string = re.sub('[ \t\n]+', ' ', 'The quick brown \n\n \t fox')
Cela supprimera tout l’onglet, les nouvelles lignes et plusieurs espaces blancs avec un seul espace blanc.
Dans certains cas, il est souhaitable de remplacer les occurrences consécutives de chaque caractère d'espacement par une seule instance de that character. Vous utiliseriez une expression régulière avec des références arrières pour le faire.
(\s)\1{1,}
correspond à n'importe quel caractère d'espacement, suivi d'une ou plusieurs occurrences de ce caractère. Maintenant, tout ce que vous avez à faire est de spécifier le premier groupe (\1
) en remplacement de la correspondance.
Envelopper ceci dans une fonction:
import re
def normalize_whitespace(string):
return re.sub(r'(\s)\1{1,}', r'\1', string)
>>> normalize_whitespace('The fox jumped over the log.')
'The fox jumped over the log.'
>>> normalize_whitespace('First line\t\t\t \n\n\nSecond line')
'First line\t \nSecond line'
Une ligne de code pour supprimer tous les espaces supplémentaires avant, après et dans une phrase:
sentence = " The fox jumped over the log. "
sentence = ' '.join(filter(None,sentence.split(' ')))
Explication:
* Les éléments restants doivent être des mots ou des mots avec des ponctuations, etc. Je n'ai pas testé cela de manière approfondie, mais cela devrait être un bon point de départ. Bonne chance!
Autre alternative
>>> import re
>>> str = 'this is a string with multiple spaces and tabs'
>>> str = re.sub('[ \t]+' , ' ', str)
>>> print str
this is a string with multiple spaces and tabs
def unPretty(S):
# given a dictionary, json, list, float, int, or even a string..
# return a string stripped of CR, LF replaced by space, with multiple spaces reduced to one.
return ' '.join( str(S).replace('\n',' ').replace('\r','').split() )
Le plus rapidement possible pour les chaînes générées par l'utilisateur est:
if ' ' in text:
while ' ' in text:
text = text.replace(' ', ' ')
Le court-circuit le rend légèrement plus rapide que la réponse complète de pythonlarry . Optez pour cela si vous recherchez l'efficacité et que vous cherchez strictement à éliminer les espaces blancs supplémentaires de la variété d'espace unique.
Cela semble aussi fonctionner:
while " " in s:
s=s.replace(" "," ")
Où la variable s représente votre chaîne.
i have tried the following method and it even works with the extreme case
like str1=' i live on earth '
' '.join(str1.split())
but if you prefer regular expression it can be done as:-
re.sub('\s+',' ',str1)
although some preprocessing has to be done in order to remove the trailing and ending space.
J'ai ma méthode simple qui ont utilisé à l'université.
line = "I have a Nice day."
end = 1000
while end != 0:
line.replace(" ", " ")
end -= 1
Cela remplacera chaque double espace par un seul espace et le fera 1000 fois. Cela signifie que vous pouvez avoir 2000 espaces supplémentaires et que vous travaillerez toujours. :)
Pour supprimer les espaces, en considérant les espaces de début, de fin et extra entre les mots, utilisez:
(? <=\s) + | ^ + (? =\s) | (? = + [\ n\0])
le premier ou traite des espaces blancs de premier plan, le second ou du début des espaces blancs de début de chaîne, et le dernier concerne les espaces blancs de fin
comme preuve d'utilisation, ce lien vous fournira un test.
https://regex101.com/r/meBYli/4
laissez-moi savoir si vous trouvez une entrée qui rompra ce code regex.
AUSSI - à utiliser avec la fonction re.split
S'il s'agit d'espaces, le fractionnement sur Aucun n'inclut pas de chaîne vide dans la valeur renvoyée.
Je n'ai pas beaucoup lu dans les autres exemples, mais je viens de créer cette méthode pour consolider plusieurs espaces consécutifs.
Il n'utilise aucune bibliothèque et, même s'il est relativement long en termes de longueur de script, sa mise en œuvre n'est pas complexe.
def spaceMatcher(command):
"""
function defined to consolidate multiple whitespace characters in
strings to a single space
"""
#initiate index to flag if more than 1 consecutive character
iteration
space_match = 0
space_char = ""
for char in command:
if char == " ":
space_match += 1
space_char += " "
Elif (char != " ") & (space_match > 1):
new_command = command.replace(space_char, " ")
space_match = 0
space_char = ""
Elif char != " ":
space_match = 0
space_char = ""
return new_command
command = None
command = str(input("Please enter a command ->"))
print(spaceMatcher(command))
print(list(spaceMatcher(command)))
string='This is a string full of spaces and taps'
string=string.split(' ')
while '' in string:
string.remove('')
string=' '.join(string)
print(string)
résultats :
Ceci est une chaîne pleine d'espaces et de robinets