Использование python и регулярных выражений для удаления повторяющихся символьных строк в слове

#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!