Як замінити пробіли на підкреслення і навпаки?


221

Я хочу замінити пробіл на підкреслення в рядку, щоб створити приємні URL-адреси. Так що наприклад:

"This should be connected" becomes "This_should_be_connected" 

Я використовую Python з Django. Чи можна це вирішити, використовуючи регулярні вирази?


1
Як цього можна досягти в шаблоні джанго. Чи є спосіб видалити пробіли. Чи є вбудований тег / фільтр для цього? Примітка: slugifyне дає бажаного результату.
користувач1144616

Відповіді:


375

Вам не потрібні регулярні вирази. У Python є вбудований рядовий метод, який виконує те, що вам потрібно:

mystring.replace(" ", "_")

29
Це не працює з іншими символами пробілу, такими як \ t або нерозривний пробіл.
Роберто Бонваллет

12
Так, ви праві, але для того, щоб поставити запитання, не потрібно враховувати ці інші пробіли.
rogeriopvl

1
чи потрібно імпортувати щось для цього? Я отримую таку помилку: AttributeError: 'buildin_function_or_method' об’єкт не має атрибута 'замінити'
Ocasta Eshu

2
Можливо, змінна, яку ви викликали на заміну, не була рядковим типом.
Снігдха Батра

4
Ця відповідь може бути заплутаною, краще запишіть її як mystring = mystring.replace ("", "_"), оскільки вона не змінює безпосередньо рядок, а повертає змінену версію.
Мехді

79

Заміна пробілів - це добре, але я б запропонував піти трохи далі, щоб обробити інші ворожі URL-адреси, такі як знаки запитання, апострофи, знаки оклику тощо.

Також зауважте, що загальний консенсус серед експертів з SEO полягає в тому, що тире віддають перевагу підкресленням 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!"))

Це цікаво. Я обов'язково скористаюся цією порадою.
Лукас

Не забудьте urllib.quote () вихід вашого urlify () - що робити, якщо s містить щось не-ascii?
zgoda

1
Це приємно - але перший RE з \ W також видалить пробіл, у результаті чого наступний RE не може нічого замінити ... Якщо ви хочете замінити інші символи на "-", між лексемами перший RE замінить на один пробіл, як зазначено - тобто s = re.sub (r "\ W", '& nbsp', s) (це може бути приголомшлива проблема форматування в StackOverflow: meta.stackexchange.com/questions/105507/… )
tiluki

2
@Triptych Що ти маєш на увазі? Африканська чи європейська ластівка?
tiluki

1
Ще одна невелика проблема з цим полягає в тому, що ви видалите всі попередні дефіси в URL-адресі, так що якби користувач намагався очистити рядок URL-адреси перед завантаженням, щоб це було чистим, воно було б позбавлене від цього. Так s = re.sub (r '[^ \ w \ s-]', '', s). Можна піти ще на крок і видалити пробіли проміжних та кінцевих пробілів, щоб ім’я файлу не закінчувалося або починалося дефісом з s = re.sub (r '[^ \ w \ s-]', '', s) .strip ()
Intenex

42

Django має функцію "slugify", яка це робить, а також інші оптимізації, сприятливі для URL-адрес. Він прихований у модулі фільтра за замовчуванням.

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

this-should-be-connected

Це не зовсім вихід, про який ви просили, але IMO краще використовувати в URL-адресах.


Це цікавий варіант, але це питання смаку чи які переваги використання дефісів замість підкреслення. Я щойно помітив, що Stackoverflow використовує дефіси, як ви пропонуєте. Але, наприклад, digg.com використовує підкреслення.
Лукас

Це, можливо, є кращим варіантом (AFAIK). Візьміть свій рядок, слугуйте його, зберігайте в SlugField і використовуйте його у вашій моделі get_absolute_url (). Ви можете легко знайти приклади в мережі.
шаню

3
@Lulu люди використовують тире, оскільки тривалий час пошукові системи розглядають тире як розділювач слів, і тому ви полегшите час, коли ви шукаєте багатослів.
Джеймс Беннетт

@Daniel Roseman чи можу я використовувати це з динамічною змінною. тому що я отримую динамічні веб-сайти як рядок у веріанному
ефемерному

Це правильна відповідь. Потрібно очистити свої URL-адреси.
кагронік

40

При цьому враховуються порожні символи, відмінні від місця, і я думаю, що це швидше, ніж використання reмодуля:

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

4
Ще важливіше, що він буде працювати для будь-якого символу пробілу або групи символів пробілу.
дшеферд

Це рішення не обробляє всіх символів пробілу. (наприклад \x8f)
Lokal_Profil

Гарний улов, @Lokal_Profil! Документація не визначає , які символи пробілів беруться до уваги.
xOneca

1
Це рішення також не збереже повторні роздільники, оскільки split () не повертає порожні елементи при використанні типового режиму "розділити на пробіл". Тобто, якщо вхід "привіт, (6 пробілів тут) світ", це призведе до "привіт, _світ" як вихід, а не "привіт, ______ світ".
FliesLikeABrick

20

Використання reмодуля:

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

Якщо у вас немає декількох пробілів або інших можливостей пробілу, як зазначено вище, ви можете просто використовувати, string.replaceяк запропонували інші.


Дякую, саме про це я і просив. Але я згоден, "string.replace" видається більш підходящим для мого завдання.
Лукас

Що, до біса, я мав намір підтримати це, але чомусь це було знято, і тепер мій голос заблокований. Вибачте Джаррет.
Дейв Лю

10

використовувати метод заміни рядка:

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

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


6

Дивно, але ця бібліотека ще не згадується

Пакет python з ім'ям python-slugify, який виконує досить непогану роботу щодо слугіфікації:

pip install python-slugify

Працює так:

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

Я використовую такий код у своїх дружніх URL-адресах:

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

Він добре працює і з символами Unicode.


1
Чи можете ви пояснити, чим це відрізняється від вбудованої функції слугування Джанго?
Енді Бейкер

4

У Python є вбудований метод на рядках під назвою замість, який використовується так:

string.replace(old, new)

Отже, ви б використовували:

string.replace(" ", "_")

У мене ця проблема була деякий час тому, і я написав код, щоб замінити символи в рядку. Я повинен почати згадувати, щоб перевірити документацію python, оскільки вони мають вбудовані функції для всього.


3

OP використовує python, але у JavaScript (що слід бути обережним, оскільки синтаксиси схожі.

// 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 (" ", "_")

якщо ви призначите це значення будь-якій змінній, воно буде працювати

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

за замовчуванням у mystring у цього немає



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

Збіг і заміни пробілу> підкресли всі файли в поточному каталозі

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.