Comment remplacer les espaces blancs par un trait de soulignement et vice versa?


221

Je veux remplacer les espaces par un trait de soulignement dans une chaîne pour créer de belles URL. Pour que par exemple:

"This should be connected" becomes "This_should_be_connected" 

J'utilise Python avec Django. Cela peut-il être résolu en utilisant des expressions régulières?


1
Comment cela peut-il être réalisé dans le modèle django. Existe-t-il un moyen de supprimer les espaces blancs. Y a-t-il un tag / filtre intégré pour ce faire? Remarque: slugifyne donne pas la sortie souhaitée.
user1144616

Réponses:


375

Vous n'avez pas besoin d'expressions régulières. Python a une méthode de chaîne intégrée qui fait ce dont vous avez besoin:

mystring.replace(" ", "_")

29
Cela ne fonctionne pas avec d'autres caractères d'espacement, tels que \ t ou un espace insécable.
Roberto Bonvallet

12
Oui, vous avez raison, mais aux fins de la question posée, il ne semble pas nécessaire de prendre en compte ces autres espaces.
rogeriopvl

1
dois-je importer quelque chose pour que cela fonctionne? J'obtiens l'erreur suivante: AttributeError: l'objet 'builtin_function_or_method' n'a pas d'attribut 'replace'
Ocasta Eshu

2
La variable que vous avez appelée replace n'était probablement pas un type de chaîne.
Snigdha Batra du

5
Cette réponse peut prêter à confusion, mieux vaut l'écrire sous mystring = mystring.replace ("", "_") car elle ne modifie pas directement la chaîne mais renvoie plutôt une version modifiée.
Mehdi

79

Remplacer les espaces est bien, mais je pourrais suggérer d'aller un peu plus loin pour gérer d'autres caractères hostiles aux URL comme les points d'interrogation, les apostrophes, les points d'exclamation, etc.

Notez également que le consensus général parmi les experts SEO est que les tirets sont préférés aux soulignés dans les URL.

import re

def urlify(s):

    # Remove all non-word characters (everything except numbers and letters)
    s = re.sub(r"[^\w\s]", '', s)

    # Replace all runs of whitespace with a single dash
    s = re.sub(r"\s+", '-', s)

    return s

# Prints: I-cant-get-no-satisfaction"
print(urlify("I can't get no satisfaction!"))

C'est intéressant. Je vais certainement utiliser ce conseil.
Lucas

N'oubliez pas d'urllib.quote () la sortie de votre urlify () - et si s contient quelque chose de non-ascii?
zgoda

1
C'est bien - mais le premier RE avec \ W supprimera également les espaces blancs avec le résultat que le RE suivant n'a rien à remplacer ... Si vous voulez remplacer vos autres caractères par '-' entre les jetons, faites remplacer le premier RE par un espace unique comme indiqué - c'est-à-dire s = re.sub (r "\ W", '& nbsp', s) (cela peut être un problème de mise en forme shonky sur StackOverflow: meta.stackexchange.com/questions/105507/… )
tiluki

2
@Triptych Que voulez-vous dire? Hirondelle africaine ou européenne?
tiluki

1
Un autre léger problème avec cela est que vous supprimez tous les tirets préexistants dans l'URL, de sorte que si l'utilisateur avait tenté de nettoyer la chaîne d'URL avant de télécharger pour être this-is-clean, il serait supprimé de thisisclean. Donc s = re.sub (r '[^ \ w \ s-]', '', s). Peut aller plus loin et supprimer les espaces de début et de fin afin que le nom de fichier ne se termine pas ou ne commence pas par un tiret avec s = re.sub (r '[^ \ w \ s-]', '', s) .strip ()
Intenex

42

Django a une fonction 'slugify' qui fait cela, ainsi que d'autres optimisations compatibles avec les URL. Il est caché dans le module defaultfilters.

>>> from django.template.defaultfilters import slugify
>>> slugify("This should be connected")

this-should-be-connected

Ce n'est pas exactement le résultat que vous avez demandé, mais IMO, il est préférable de l'utiliser dans les URL.


C'est une option intéressante, mais est-ce une question de goût ou quels sont les avantages d'utiliser des tirets au lieu de traits de soulignement. Je viens de remarquer que Stackoverflow utilise des tirets comme vous le suggérez. Mais digg.com utilise par exemple des traits de soulignement.
Lucas

Cela se trouve être l'option préférée (AFAIK). Prenez votre chaîne, slugifiez-la, stockez-la dans un SlugField et utilisez-la dans get_absolute_url () de votre modèle. Vous pouvez facilement trouver des exemples sur le net.
shanyu

3
Les gens de @Lulu utilisent des tirets parce que, pendant longtemps, les moteurs de recherche ont traité les tirets comme des séparateurs de mots et ainsi vous auriez plus de facilité à trouver des recherches multi-mots.
James Bennett

@Daniel Roseman puis-je l'utiliser avec une variable dynamique. comme je reçois des sites Web dynamiques sous forme de chaîne dans un véritable
éphémère

C'est la bonne réponse. Vous devez nettoyer vos URL.
kagronick

40

Cela prend en compte les caractères vides autres que l'espace et je pense que c'est plus rapide que d'utiliser le remodule:

url = "_".join( title.split() )

4
Plus important encore, cela fonctionnera pour tout caractère d'espacement ou groupe de caractères d'espacement.
dshepherd

Cette solution ne gère pas tous les caractères d'espacement. (par exemple \x8f)
Lokal_Profil

Bonne prise, @Lokal_Profil! La documentation ne précise pas quels caractères d'espaces sont pris en compte.
xOneca

1
Cette solution ne conservera pas non plus les délimiteurs de répétition, car split () ne renvoie pas les éléments vides lors de l'utilisation du comportement par défaut "split on white". Autrement dit, si l'entrée est "bonjour, (6 espaces ici) monde", cela se traduira par "bonjour, _world" en sortie, plutôt que "bonjour, ______ monde".
FliesLikeABrick

20

Utilisation du remodule:

import re
re.sub('\s+', '_', "This should be connected") # This_should_be_connected
re.sub('\s+', '_', 'And     so\tshould this')  # And_so_should_this

À moins que vous n'ayez plusieurs espaces ou d'autres possibilités d'espaces comme ci-dessus, vous pouvez simplement utiliser string.replacecomme d'autres l'ont suggéré.


Merci, c'est exactement ce que je demandais. Mais je suis d'accord, le "string.replace" semble plus adapté à ma tâche.
Lucas

Bon sang, je voulais voter pour cela, mais pour une raison quelconque, il a été rejeté et maintenant mon vote est verrouillé. Désolé Jarret.
Dave Liu

10

utilisez la méthode de remplacement de chaîne:

"this should be connected".replace(" ", "_")

"this_should_be_disconnected".replace("_", " ")


6

Étonnamment, cette bibliothèque n'est pas encore mentionnée

package python nommé python-slugify, qui fait un très bon travail de slugification:

pip install python-slugify

Fonctionne comme ceci:

from slugify import slugify

txt = "This is a test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = "This -- is a ## test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = 'C\'est déjà l\'été.'
r = slugify(txt)
self.assertEquals(r, "cest-deja-lete")

txt = 'Nín hǎo. Wǒ shì zhōng guó rén'
r = slugify(txt)
self.assertEquals(r, "nin-hao-wo-shi-zhong-guo-ren")

txt = 'Компьютер'
r = slugify(txt)
self.assertEquals(r, "kompiuter")

txt = 'jaja---lol-méméméoo--a'
r = slugify(txt)
self.assertEquals(r, "jaja-lol-mememeoo-a") 

5

J'utilise le code suivant pour mes URL conviviales:

from unicodedata import normalize
from re import sub

def slugify(title):
    name = normalize('NFKD', title).encode('ascii', 'ignore').replace(' ', '-').lower()
    #remove `other` characters
    name = sub('[^a-zA-Z0-9_-]', '', name)
    #nomalize dashes
    name = sub('-+', '-', name)

    return name

Cela fonctionne aussi bien avec les caractères Unicode.


1
Pourriez-vous expliquer en quoi cela diffère de la fonction intégrée de slugify de Django?
Andy Baker

4

Python a une méthode intégrée sur les chaînes appelée replace qui est utilisée comme suit:

string.replace(old, new)

Vous utiliseriez donc:

string.replace(" ", "_")

J'ai eu ce problème il y a quelque temps et j'ai écrit du code pour remplacer les caractères d'une chaîne. Je dois commencer à me rappeler de vérifier la documentation de python car ils ont des fonctions intégrées pour tout.


3

OP utilise python, mais en javascript (quelque chose à faire attention car les syntaxes sont similaires.

// only replaces the first instance of ' ' with '_'
"one two three".replace(' ', '_'); 
=> "one_two three"

// replaces all instances of ' ' with '_'
"one two three".replace(/\s/g, '_');
=> "one_two_three"

3
mystring.replace (" ", "_")

si vous attribuez cette valeur à une variable, cela fonctionnera

s = mystring.replace (" ", "_")

par défaut mystring n'aura pas cette



-3
perl -e 'map { $on=$_; s/ /_/; rename($on, $_) or warn $!; } <*>;'

Match and replace space> soulignement de tous les fichiers du répertoire courant

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.