Jak zastąpić białe znaki podkreśleniem i odwrotnie?

221

Chcę zastąpić biały znak podkreśleniem w ciągu, aby utworzyć ładne adresy URL. Tak więc na przykład:

"This should be connected" becomes "This_should_be_connected" 

Używam Pythona z Django. Czy można to rozwiązać za pomocą wyrażeń regularnych?

Lucas
źródło
1
Jak można to osiągnąć w szablonie django. Czy jest jakiś sposób na usunięcie białych spacji. Czy jest w tym wbudowany tag / filtr? Uwaga: slugifynie daje pożądanego wyniku.
user1144616,

Odpowiedzi:

375

Nie potrzebujesz wyrażeń regularnych. Python ma wbudowaną metodę ciągu, która wykonuje to, czego potrzebujesz:

mystring.replace(" ", "_")
rogeriopvl
źródło
29
Nie działa to z innymi znakami spacji, takimi jak \ t lub spacja niełamiąca.
Roberto Bonvallet,
12
Tak, masz rację, ale dla celów zadanego pytania nie wydaje się konieczne uwzględnienie tych innych spacji.
rogeriopvl
1
czy muszę coś zaimportować, aby to działało? Otrzymuję następujący błąd: AttributeError: obiekt „wbudowana_funkcja_lub_metoda” nie ma atrybutu „zamień”
Ocasta Eshu
2
Prawdopodobnie zmienna, którą wywołałeś replace, nie była łańcuchem znaków.
Snigdha Batra,
4
Ta odpowiedź może być myląca, lepiej napisz ją jako mystring = mystring.replace („”, „_”), ponieważ nie zmienia ona bezpośrednio łańcucha, a raczej zwraca zmienioną wersję.
Mehdi,
79

Zastępowanie spacji jest w porządku, ale mogę zasugerować pójście nieco dalej w celu obsługi innych znaków nieprzyjaznych adresom URL, takich jak znaki zapytania, apostrofy, wykrzykniki itp.

Należy również pamiętać, że ogólny konsensus wśród ekspertów SEO jest taki, że kreski są preferowane zamiast znaków podkreślenia w adresach 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!"))
Tryptyk
źródło
To jest interesujące. Zdecydowanie skorzystam z tej rady.
Lucas
Pamiętaj o urllib.quote () danych wyjściowych swojej urlify () - co jeśli s zawiera coś innego niż ascii?
zgoda
1
To miłe - ale pierwsze RE z \ W usunie również białe spacje, w wyniku czego kolejne RE nie ma nic do zastąpienia ... Jeśli chcesz zamienić inne postacie na „-” między tokenami, pierwsze RE zamień na pojedyncza spacja, jak wskazano - tj. s = re.sub (r "\ W", '& nbsp', s) (może to być niewyraźny problem z formatowaniem w StackOverflow: meta.stackexchange.com/questions/105507/… )
tiluki
2
@Triptych Co masz na myśli? Jaskółka afrykańska czy europejska?
tiluki
1
Kolejnym niewielkim problemem jest to, że usuwasz istniejące wcześniej myślniki w adresie URL, więc jeśli użytkownik próbował wyczyścić ciąg adresu URL przed przesłaniem go do tego-jest-czysty, zostanie on usunięty do tego plikuisc. Więc s = re.sub (r '[^ \ w \ s-]', '', s). Może pójść o krok dalej i usunąć początkowe i końcowe białe spacje, aby nazwa pliku nie kończyła się ani nie zaczynała od myślnika s = re.sub (r '[^ \ w \ s-]', '', s) .strip ()
Intenex,
42

Django ma funkcję „slugify”, która to robi, a także inne optymalizacje przyjazne adresom URL. Jest ukryty w domyślnym module filtrów.

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

this-should-be-connected

Nie jest to dokładnie wynik, o który prosiłeś, ale IMO lepiej jest użyć w adresach URL.

Daniel Roseman
źródło
Jest to interesująca opcja, ale czy jest to kwestia gustu lub jakie są zalety używania łączników zamiast znaków podkreślenia. Właśnie zauważyłem, że Stackoverflow używa łączników, tak jak sugerujesz. Ale na przykład digg.com używa podkreślników.
Lucas
Jest to preferowana opcja (AFAIK). Weź swój ciąg, slugify, przechowuj w SlugField i wykorzystaj w get_absolute_url () w swoim modelu. Możesz łatwo znaleźć przykłady w sieci.
shanyu
3
@Lulu ludzie używają myślników, ponieważ przez długi czas wyszukiwarki traktowały myślniki jako separatory słów, dzięki czemu łatwiej będzie ci się znaleźć w wyszukiwaniu wielu słów.
James Bennett
@Daniel Roseman mogę używać tego z dynamicznie zmienną. gdy dostaję dynamiczne strony internetowe jako ciąg znaków w
efemeryczny
To jest właściwa odpowiedź. Musisz zdezynfekować swoje adresy URL.
kagronick
40

Uwzględnia to puste znaki inne niż spacja i myślę, że jest to szybsze niż użycie remodułu:

url = "_".join( title.split() )
xOneca
źródło
4
Co ważniejsze, będzie działać na dowolny znak lub grupę białych znaków.
dshepherd
To rozwiązanie nie obsługuje wszystkich białych znaków. (np. \x8f)
Lokal_Profil
Dobry połów, @Lokal_Profil! Dokumentacja nie określa, jakie znaki odstępu są brane pod uwagę.
xOneca,
1
To rozwiązanie nie zachowa również powtarzających się separatorów, ponieważ split () nie zwraca pustych elementów, gdy używane jest domyślne zachowanie „split on white space”. Oznacza to, że jeśli dane wejściowe to „hello, (6 spacji tutaj) world”, spowoduje to „hello, _world” jako wyjście, a nie „hello, ______ world”.
FliesLikeABrick,
20

Korzystanie z remodułu:

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

O ile nie masz wielu spacji lub innych możliwości białych znaków, jak wyżej, możesz po prostu użyć string.replacetego, co sugerowali inni.

Jarret Hardie
źródło
Dziękuję, właśnie o to prosiłem. Ale zgadzam się, że „string.replace” wydaje się bardziej odpowiedni do mojego zadania.
Lucas
Co do cholery, chciałem głosować za tym, ale z jakiegoś powodu został on przegłosowany i teraz mój głos jest zamknięty. Przepraszam Jarret.
Dave Liu,
10

użyj metody zamiany ciągu:

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

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

mdirolf
źródło
6

O dziwo ta biblioteka jeszcze nie wspomniana

pakiet python o nazwie python-slugify, który wykonuje całkiem niezłą robotę:

pip install python-slugify

Działa tak:

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") 
Yash
źródło
5

Dla moich przyjaznych adresów URL używam następującego kodu:

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

Działa również dobrze ze znakami Unicode.

Armandas
źródło
1
Czy możesz wyjaśnić, czym różni się to od wbudowanej funkcji slugify w Django?
Andy Baker,
4

Python ma wbudowaną metodę ciągów o nazwie replace, która jest używana w następujący sposób:

string.replace(old, new)

Więc użyłbyś:

string.replace(" ", "_")

Miałem ten problem jakiś czas temu i napisałem kod zastępujący znaki w ciągu. Muszę zacząć pamiętać, aby sprawdzić dokumentację Pythona, ponieważ mają one wbudowane funkcje do wszystkiego.


źródło
3

OP używa Pythona, ale w javascript (należy zachować ostrożność, ponieważ składnie są podobne.

// 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"
twmulloy
źródło
3
mystring.replace (" ", "_")

jeśli przypiszesz tę wartość do dowolnej zmiennej, zadziała

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

domyślnie mystring nie ma tego

Rajesz
źródło
3

Możesz spróbować zamiast tego:

mystring.replace(r' ','-')
Meghaa Yadav
źródło
-3
perl -e 'map { $on=$_; s/ /_/; rename($on, $_) or warn $!; } <*>;'

Dopasuj i zamień spację> podkreślenie wszystkich plików w bieżącym katalogu


źródło