Supposons que cette chaîne:
The fox jumped over the log.
Se transformer en:
The fox jumped over the log.
Quelle est la plus simple (1-2 lignes) pour y parvenir, sans se diviser et entrer dans des listes?
Supposons que cette chaîne:
The fox jumped over the log.
Se transformer en:
The fox jumped over the log.
Quelle est la plus simple (1-2 lignes) pour y parvenir, sans se diviser et entrer dans des listes?
Réponses:
>>> import re
>>> re.sub(' +', ' ', 'The quick brown fox')
'The quick brown fox'
string.split
gère également toutes sortes d'espaces blancs.
re.sub(' {2,}', ' ', 'The quick brown fox')
pour empêcher les remplacements redondants d'un espace unique par un espace unique .
foo
est votre chaîne:
" ".join(foo.split())
Soyez averti bien que cela supprime "tous les espaces blancs (espace, tabulation, retour à la ligne, retour, saut de page)" (merci à hhsaffar , voir commentaires). C'est-à-dire, "this is \t a test\n"
finira effectivement par "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 une bête noire dans PEP 8 , comme mentionné par l'utilisateur Martin Thoma dans les commentaires.
r"\s\s+"
qu'elle n'essaye pas de remplacer des espaces déjà uniques.
"\s{2,}"
au lieu d'une solution de contournement pour ne pas connaître le comportement regex modérément avancé?
s
, mais renvoie la nouvelle valeur.
\s+
entraînerait la ligne à lire "remplacer un ou plusieurs espaces par un espace", plutôt que "remplacer deux ou plusieurs espaces par un espace". Le premier me fait immédiatement arrêter et penser "Pourquoi remplacer un espace par un espace? C'est idiot." Pour moi, c'est une odeur de code (très mineure). En fait , je me attends pas qu'il y ait une différence de performance du tout entre les deux, car il va être copier dans une nouvelle chaîne de toute façon, et doit cesser et le test quel que soit l'endroit où est copié l'espace à partir .
\s\s+
car cela ne normalisera pas un caractère TAB dans un espace normal. un SPACE + TAB est remplacé de cette façon.
Utiliser des expressions rationnelles avec "\ s" et faire de simples string.split () supprimera également d' autres espaces comme les retours à la ligne, les retours chariot et les tabulations. À moins que cela ne soit souhaité, pour ne faire que plusieurs espaces , je présente ces exemples.
J'ai utilisé 11 paragraphes, 1000 mots, 6665 octets de Lorem Ipsum pour obtenir des tests de temps réalistes et utilisé des espaces supplémentaires de longueur aléatoire tout au long:
original_string = ''.join(word + (' ' * random.randint(1, 10)) for word in lorem_ipsum.split(' '))
Le one-liner fera essentiellement une bande de tous les espaces de début / fin, et il conserve un espace de début / fin (mais seulement UN ;-).
# 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 " Gardez à l' esprit que le principal while
version" a fait une copie de la original_string
, comme je crois une fois modifiée lors de la première exécution, les exécutions successives seraient plus rapides (ne serait-ce que par un peu). Comme cela ajoute du temps, j'ai ajouté cette copie de chaîne aux deux autres afin que les heures ne montrent la différence que dans la logique. stmt
sur les timeit
instances ne sera exécutée une fois ; comme je l'ai fait à l'origine, la while
boucle fonctionnait sur le même label original_string
, donc la deuxième manche, il n'y aurait rien à faire. La façon dont il est configuré maintenant, appeler une fonction, en utilisant deux étiquettes différentes, ce n'est pas un problème. J'ai ajouté des assert
déclarations à tous les travailleurs pour vérifier que nous changeons quelque chose à chaque itération (pour ceux qui peuvent être douteux). Par exemple, changez cela 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 qu'une boucle while soit la plus rapide, suivie de la division / jointure de chaîne Pythonic et de l'expression régulière tirant vers l'arrière.
Pour les chaînes non triviales , il semble qu'il y ait un peu plus à considérer. 32 bits 2,7? C'est regex à la rescousse! 2.7 64 bits? Une while
boucle est préférable, avec une marge décente. 32 bits 3.2, allez avec le "bon" join
. 64 bits 3.3, optez pour une while
boucle. Encore.
En fin de compte, on peut améliorer les performances si / où / quand cela est nécessaire , mais il est toujours préférable de se rappeler le mantra :
IANAL, YMMV, Caveat Emptor!
' '.join(the_string.split())
car c'est le cas d'usage habituel mais j'aimerais vous dire merci pour votre travail!
' '.join(p for p in s.split(' ') if p)
<- toujours perdu des espaces de plomb / de fin, mais représentait plusieurs espaces. Pour les garder, faut faire comme parts = s.split(' '); (' ' if not parts[0] else '') + ' '.join(p for p in s.split(' ') if p) + (' ' if not parts[-1] else '')
!
Je suis d'accord avec le commentaire de Paul McGuire. Tome,
' '.join(the_string.split())
est largement préférable à fouetter une expression régulière.
Mes mesures (Linux et Python 2.5) montrent que le split-then-join est presque cinq fois plus rapide que de faire le "re.sub (...)", et encore trois fois plus rapide si vous précompilez le regex une fois et effectuez l'opération plusieurs fois. Et il est de toute façon plus facile à comprendre - beaucoup plus Pythonic.
Vous pouvez également utiliser la technique de fractionnement de chaînes dans un Pandas DataFrame sans avoir besoin d'utiliser .apply (..), qui est utile si vous devez effectuer l'opération rapidement sur un grand nombre de chaînes. Ici, c'est 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 tous les onglets, les nouvelles lignes et les multiples espaces blancs avec un seul espace blanc.
J'ai essayé la méthode suivante et cela fonctionne même avec le cas extrême comme:
str1=' I live on earth '
' '.join(str1.split())
Mais si vous préférez une expression régulière, cela peut être fait comme:
re.sub('\s+', ' ', str1)
Bien qu'un certain prétraitement doive être fait afin de supprimer l'espace de fin et de fin.
Dans certains cas, il est souhaitable de remplacer les occurrences consécutives de chaque caractère d'espacement par une seule instance de ce caractère. Vous utiliseriez une expression régulière avec des références arrières pour ce 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 devez faire est de spécifier le premier groupe ( \1
) comme remplacement pour la correspondance.
Envelopper cela 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 devraient être des mots ou des mots avec des signes de ponctuation, etc. Je n'ai pas testé cela de manière approfondie, mais cela devrait être un bon point de départ. Bonne chance!
Solution pour les développeurs Python:
import re
text1 = 'Python Exercises Are Challenging Exercises'
print("Original string: ", text1)
print("Without extra spaces: ", re.sub(' +', ' ', text1))
Production:
Original string: Python Exercises Are Challenging Exercises
Without extra spaces: Python Exercises Are Challenging Exercises
Le plus rapide que vous pouvez obtenir pour les chaînes générées par l'utilisateur est:
if ' ' in text:
while ' ' in text:
text = text.replace(' ', ' ')
Le court-circuitage le rend légèrement plus rapide que la réponse complète de pythonlarry . Allez-y si vous recherchez l'efficacité et que vous cherchez strictement à éliminer les espaces supplémentaires de la variété à espace unique .
Assez surprenant - personne n'a publié de fonction simple qui sera beaucoup plus rapide que TOUTES les autres solutions publiées. Ça y est:
def compactSpaces(s):
os = ""
for c in s:
if c != " " or os[-1] != " ":
os += c
return os
S'il s'agit d'espaces blancs, le fractionnement sur Aucun n'inclura pas de chaîne vide dans la valeur renvoyée.
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
Pour supprimer les espaces blancs, en tenant compte des espaces blancs de début, de fin et supplémentaires entre les mots, utilisez:
(?<=\s) +|^ +(?=\s)| (?= +[\n\0])
Le premier or
concerne les principaux espaces blancs, le secondor
de début début des espaces blancs de début de chaîne et le dernier les espaces blancs de fin.
Pour preuve d'utilisation, ce lien vous fournira un test.
https://regex101.com/r/meBYli/4
Il doit être utilisé avec la fonction re.split .
J'ai ma méthode simple que j'ai utilisée au collège.
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 fonctionnera toujours. :)
J'ai une méthode simple sans diviser:
a = "Lorem Ipsum Darum Diesrum!"
while True:
count = a.find(" ")
if count > 0:
a = a.replace(" ", " ")
count = a.find(" ")
continue
else:
break
print(a)
import re
Text = " You can select below trims for removing white space!! BR Aliakbar "
# trims all white spaces
print('Remove all space:',re.sub(r"\s+", "", Text), sep='')
# trims left space
print('Remove leading space:', re.sub(r"^\s+", "", Text), sep='')
# trims right space
print('Remove trailing spaces:', re.sub(r"\s+$", "", Text), sep='')
# trims both
print('Remove leading and trailing spaces:', re.sub(r"^\s+|\s+$", "", Text), sep='')
# replace more than one white space in the string with one white space
print('Remove more than one space:',re.sub(' +', ' ',Text), sep='')
Résultat:
Supprimer tout espace: vous pouvez sélectionner les bords inférieurs pour supprimer les espaces blancs! BR Aliakbar
Supprimer les espaces de fin: Vous pouvez sélectionner ci-dessous les garnitures pour supprimer les espaces blancs !! BR Aliakbar Supprimer les espaces de début et de fin: Vous pouvez sélectionner ci-dessous les garnitures pour supprimer les espaces blancs !! BR Aliakbar Supprimer plus d'un espace: Vous pouvez sélectionner ci-dessous les garnitures pour supprimer les espaces blancs !! BR Aliakbar
Je n'ai pas beaucoup lu dans les autres exemples, mais je viens de créer cette méthode pour consolider plusieurs caractères d'espace consécutifs.
Il n'utilise aucune bibliothèque, et bien qu'il soit relativement long en termes de longueur de script, ce n'est pas une implémentation complexe:
def spaceMatcher(command):
"""
Function defined to consolidate multiple whitespace characters in
strings to a single space
"""
# Initiate index to flag if more than one 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)))