Разделение строк в требуемом формате, Pythonic? (с или без Regex) - PullRequest
6 голосов
/ 17 февраля 2009

У меня есть строка в формате:

t='@abc @def Hello this part is text'

Я хочу получить это:

l=["abc", "def"] 
s='Hello this part is text'

Я сделал это:

a=t[t.find(' ',t.rfind('@')):].strip()
s=t[:t.find(' ',t.rfind('@'))].strip()
b=a.split('@')
l=[i.strip() for i in b][1:]

Он работает по большей части, но не работает, когда текстовая часть имеет символ '@'. Например, когда:

t='@abc @def My email is red@hjk.com'

это не удалось. @Names есть в начале, и после @names может быть текст, который может содержать @.

Ясно, что я могу сначала добавить пробел и найти первое слово без '@'. Но это не кажется элегантным решением.

Что такое питонный способ решения этой проблемы?

Ответы [ 7 ]

13 голосов
/ 17 февраля 2009

Опираясь на усилия мистера Топфа:

import re
rx = re.compile("((?:@\w+ +)+)(.*)")
t='@abc   @def  @xyz Hello this part is text and my email is foo@ba.r'
a,s = rx.match(t).groups()
l = re.split('[@ ]+',a)[1:-1]
print l
print s

печать:

['abc', 'def', 'xyz']
Здравствуйте, эта часть является текстом, и мой адрес электронной почты foo@ba.r


Справедливо призван к ответу hasen j , позвольте мне уточнить, как это работает:

/@\w+ +/

соответствует одному тегу - @, за которым следует хотя бы один буквенно-цифровой или _, за которым следует хотя бы один пробел. + является жадным, поэтому, если есть несколько пробелов, он захватит их все.

Чтобы соответствовать любому количеству этих тегов, нам нужно добавить плюс (одну или несколько вещей) в шаблон для тега; поэтому нам нужно сгруппировать его в скобках:

/(@\w+ +)+/

, который соответствует одному или нескольким тегам и, будучи жадным, соответствует всем им. Однако эти скобки теперь смешиваются с нашими группами захвата, поэтому мы отменяем это, превращая их в анонимную группу:

/(?:@\w+ +)+/

Наконец, мы превращаем это в группу захвата и добавляем еще одну, чтобы смести остальные:

/((?:@\w+ +)+)(.*)/

Последняя разбивка для подведения итогов:

((?:@\w+ +)+)(.*)
 (?:@\w+ +)+
 (  @\w+ +)
    @\w+ +

Обратите внимание, что при рассмотрении этого я улучшил его - \ w не обязательно должен быть в наборе, и теперь он допускает наличие нескольких пробелов между тегами. Спасибо, hasen-j!

7 голосов
/ 17 февраля 2009
t='@abc @def Hello this part is text'

words = t.split(' ')

names = []
while words:
    w = words.pop(0)
    if w.startswith('@'):
        names.append(w[1:])
    else:
        break

text = ' '.join(words)

print names
print text
5 голосов
/ 17 февраля 2009

Как насчет этого:

  1. Расщепление по пробелам.
  2. foreach word, отметьте

    2,1. если слово начинается с @, нажмите в первый список

    2.2. в противном случае просто объедините оставшиеся слова пробелами.

3 голосов
/ 17 февраля 2009

[ edit : это реализует то, что было предложено Усамой выше]

Это создаст L на основе переменных @ в начале строки, а затем, когда будет найден не @ var, просто возьмите оставшуюся строку.

t = '@one @two @three some text   afterward with @ symbols@ meow@meow'

words = t.split(' ')         # split into list of words based on spaces
L = []
s = ''
for i in range(len(words)):  # go through each word
    word = words[i]
    if word[0] == '@':       # grab @'s from beginning of string
        L.append(word[1:])
        continue
    s = ' '.join(words[i:])  # put spaces back in
    break                    # you can ignore the rest of the words

Вы можете изменить этот код, чтобы он был меньше кода, но я пытаюсь сделать то, что происходит, очевидным.

3 голосов
/ 17 февраля 2009

Вы также можете использовать регулярные выражения:

import re
rx = re.compile("@([\w]+) @([\w]+) (.*)")
t='@abc @def Hello this part is text and my email is foo@ba.r'
a,b,s = rx.match(t).groups()

Но все зависит от того, как могут выглядеть ваши данные. Так что вам может понадобиться настроить его. В основном он создает группу с помощью () и проверяет, что в них разрешено.

3 голосов
/ 17 февраля 2009
 [i.strip('@') for i in t.split(' ', 2)[:2]]     # for a fixed number of @def
 a = [i.strip('@') for i in t.split(' ') if i.startswith('@')]
 s = ' '.join(i for i in t.split(' ') if not i.startwith('@'))
1 голос
/ 19 февраля 2009

Вот еще один вариант, который использует split () и без регулярных выражений:

t='@abc @def My email is red@hjk.com'
tags = []
words = iter(t.split())

# iterate over words until first non-tag word
for w in words:
  if not w.startswith("@"):
    # join this word and all the following
    s = w + " " + (" ".join(words))
    break
  tags.append(w[1:])
else:
  s = "" # handle string with only tags

print tags, s

Вот более короткая, но, возможно, немного загадочная версия, которая использует регулярное выражение для поиска первого пробела, за которым следует не-символ:

import re
t = '@abc @def My email is red@hjk.com @extra bye'
m = re.search(r"\s([^@].*)$", t)
tags = [tag[1:] for tag in t[:m.start()].split()]
s = m.group(1)
print tags, s # ['abc', 'def'] My email is red@hjk.com @extra bye

Это не работает должным образом, если нет тегов или нет текста. Формат не указан. Вам нужно будет предоставить больше тестовых случаев для проверки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...