#python #regex #pandas #string #duplicates
#python #регулярное выражение #панды #строка #дубликаты
Вопрос:
Я использую pandas
in python
для очистки и подготовки некоторых данных путем сортировки слов в строке в алфавитном порядке и удаления повторяющихся символьных строк в слове
т. е. "informative text about texting"
стало бы "about informative ing text"
Моя попытка (ниже) сортирует слова в алфавитном порядке и удаляет повторяющиеся слова, но не удаляет повторяющиеся слова с дополнительными символами с обеих сторон.
df = pd.DataFrame({'raw':['informative text about texting','some more text text']})
df['cleaned'] = df['raw'].str.split().apply(lambda x: sorted(OrderedDict.fromkeys(x).keys())).str.join(' ')
df.to_dict()
>>> {'raw': {0: 'informative text about texting', 1: 'some more text text'},
'cleaned': {0: 'about informative text texting', 1: 'more some text'}}
Есть ли способ сделать это с помощью regex
?
Спасибо!
Комментарии:
1. Речь идет о 2 словах, содержащих не менее 3 символов? regex101.com/r/3d4gTc/1
2. @FourthBird, классное решение, но, боюсь, недостаточно общее. Я пытаюсь идентифицировать символьные строки, которые (повторяются) (либо как слово, либо внутри слова), и удалить дубликаты.
Ответ №1:
Конечно, есть способ сделать это с помощью регулярных выражений, но это может быть не совсем необходимо. Можно выбрать что-то вроде этого:
string = "informative text about texting"
new_string = string.replace("text", "").replace(" ", " ")
Выше мы заменяем "text"
на nothing, а затем заменяем двойной пробел одним пробелом. Нам нужно заменить двойные пробелы, потому что, когда строка содержит "text"
пробел с обеих сторон, она удалит "text"
и оставит два пробела.
Использование регулярных выражений:
string = "informative text about texting"
new_string = re.sub(r"stext|text", "", string)
Это регулярное выражение ищет пробел, который предшествует "text"
( stext
) , а затем использует оператор |
as или, за которым следует text
to , также соответствует just "text"
.
Редактировать
Давайте рассмотрим два примера:
"foo bar baz bar"
"foo bar baz barr"
Если задана первая строка, вывод должен быть "foo bar baz"
, а если задана вторая строка, вывод должен быть "foo bar baz r"
Итак, как мы можем это сделать? Во-первых, нам нужно рассмотреть, как мы можем удалить дубликаты в строке. В этом примере я использую set
для этого. Чтобы удалить базовые дубликаты, подобные "bar bar"
(не сложные дубликаты, подобные "bar barr"
):
unique = set(string.split())
Затем мы можем присоединиться unique
к using join
, чтобы иметь возможность регулярно выражать его, например:
new = " ".join(unique)
Затем мы можем перебирать каждое слово unique
и регулярно выражать всю строку с каждым словом, чтобы мы могли удалить сложные дубликаты, о которых я упоминал выше:
for word in unique:
pattern = fr"({word}(?=[^s]))|((?<=[^s]){word})"
new = re.sub(pattern, "", new)
Теперь весь скрипт должен выглядеть следующим образом:
unique = set(string.split())
new = " ".join(unique)
for word in unique:
pattern = fr"({word}(?=[^s]))|((?<=[^s]){word})"
new = re.sub(pattern, "", new)
Объяснение регулярных выражений
({word}(?=[^s]))|((?<=[^s]){word})
Это регулярное выражение использует как предварительный, так и обратный просмотр. Вы можете задать себе этот вопрос: какие критерии должны быть выполнены для замены строки символов. Ну, слово разделяется пробелами. Итак, используя предварительный просмотр, мы можем искать строки символов, которые не предшествуют пробелу:
({word}](?=[^s]))
[^s]
Совпадающие символы, которые не являются пробелом. Затем мы можем использовать lookbehind таким же образом, чтобы регулярное выражение соответствовало строкам символов, которые не следуют за пробелом:
((?<=[^s]){word})
Затем мы объединяем их с or
помощью operator (
) для завершения шаблона:
({word}(?=[^s]))|((?<=[^s]){word})
Комментарии:
1. Спасибо за это! К сожалению, я не знаю, что слово
"text"
является повторяющимся набором символов (это был просто пример); есть ли способ сначала идентифицировать повторяющиеся символы, а затем использоватьstr.replace
?2. @SamShort понял. Итак, допустим, строка
"foo bar baz bar"
. Поскольку"bar"
появляется более одного раза, тогда вы захотите удалить повторяющиеся экземпляры"bar"
?3. Да! Точно. Ваш пример намного лучше. Однако существует дополнительная сложность, если строка
foo bar baz barr
, которую я также хочу удалитьbar
. Я мог бы смириться с тем, что результатом будет либоfoo bar baz r
илиfoo bar baz
4. @SamShort спасибо за разъяснение! Я буду работать над обновленным ответом!
5. Большое спасибо, @gmdev!