Как заменить пробелы подчеркиванием и наоборот?


221

Я хочу заменить пробел на подчеркивание в строке, чтобы создать красивые URL. Так что например:

"This should be connected" becomes "This_should_be_connected" 

Я использую Python с Django. Можно ли это решить с помощью регулярных выражений?


1
Как это может быть достигнуто в шаблоне Django. Есть ли способ убрать пробелы. Есть ли встроенный тег / фильтр для этого? Примечание: slugifyне дает желаемого результата.
user1144616

Ответы:


375

Вам не нужны регулярные выражения. Python имеет встроенный строковый метод, который делает то, что вам нужно:

mystring.replace(" ", "_")

29
Это не работает с другими пробельными символами, такими как \ t или неразрывный пробел.
Роберто Бонваллет

12
Да, вы правы, но для целей поставленного вопроса, кажется, нет необходимости принимать во внимание эти другие пробелы.
rogeriopvl

1
мне нужно импортировать что-нибудь, чтобы это работало? Я получаю следующую ошибку: AttributeError: у объекта 'builtin_function_or_method' нет атрибута 'replace'
Ocasta Eshu

2
Вероятно, переменная, которую вы называете replace, не была строковым типом.
Снигдха Батра

5
Этот ответ может ввести в заблуждение, лучше написать его как 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?
Згода

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

2
@Triptych Что ты имеешь в виду? Африканская или европейская ласточка?
Тилуки

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

42

В Django есть функция 'slugify', которая делает это, а также другие оптимизированные для URL оптимизации. Это скрыто в модуле defaultfilters.

>>> 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 люди используют тире, потому что в течение долгого времени поисковые системы рассматривали дефисы как разделители слов, и поэтому в поисках по нескольким словам вам будет легче.
Джеймс Беннетт

@ Даниэль Роузман я могу использовать это с динамически переменными. как я получаю динамические веб-сайты в виде строки в проверяемом
эфемерно

Это правильный ответ. Вы должны очистить ваши URL.
kagronick

40

Это учитывает пустые символы, кроме пробела, и я думаю, что это быстрее, чем с помощью reмодуля:

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

4
Что еще более важно это будет работать для любого символа пробела или группы символов пробела.
dshepherd

Это решение не обрабатывает все пробельные символы. (например \x8f)
Lokal_Profil

Хороший улов, @Lokal_Profil! В документации не указывается, какие символы пробелов учитываются.
xOneca

1
Это решение также не сохранит повторяющиеся разделители, так как split () не возвращает пустые элементы при использовании поведения по умолчанию «разбивка на пробелах». То есть, если вход «hello, (здесь 6 пробелов) world», это приведет к «hello, _world» в качестве вывода, а не «hello, ______ world».
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

Он отлично работает и с символами Юникода.


1
Не могли бы вы объяснить, чем это отличается от встроенной функции Slugify Django?
Энди Бейкер

4

В Python есть встроенный метод для строк, называемый replace, который используется следующим образом:

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.