Khớp và loại bỏ các ký tự trùng lặp: Thay thế nhiều (3+) lần xuất hiện không liên tiếp


9

Tôi đang tìm kiếm một regexmô hình sẽ phù hợp với sự xuất hiện thứ ba, thứ tư, ... của mỗi nhân vật. Nhìn bên dưới để làm rõ:

Ví dụ tôi có chuỗi sau:

111aabbccxccybbzaa1

Tôi muốn thay thế tất cả các nhân vật trùng lặp sau lần xuất hiện thứ hai. Đầu ra sẽ là:

11-aabbccx--y--z---

Một số mẫu regex mà tôi đã thử cho đến nay:

Sử dụng regex sau đây tôi có thể tìm thấy lần xuất hiện cuối cùng của mỗi nhân vật: (.)(?=.*\1)

Hoặc sử dụng cái này tôi có thể làm nó cho các bản sao liên tiếp nhưng không cho bất kỳ bản sao nào: ([a-zA-Z1-9])\1{2,}


1
Công cụ regex nào bạn có kế hoạch sử dụng với regex?
Wiktor Stribiż

1
Bạn chỉ có thể làm điều đó với một regex hỗ trợ giao diện chiều rộng vô hạn, vì vậy tùy chọn duy nhất của bạn là mô-đun regex Python PyPi sau đó. Sử dụng nó với (.)(?<=^(?:(?:(?!\1).)*\1){2,}(?:(?!\1).)*\1)regex. Bản demo .
Wiktor Stribiż

3
@ WiktorStribiżew Điều đó có tốt hơn (.)(?<=(.*\1){3})không?
Stefan Pochmann

2
@StefanPochmann Vâng, (.)(?<=(?:.*\1){3})cũng sẽ thực hiện công việc, nhưng tất cả những điều này đều không tốt vì việc quay lại quá mức có thể gây ra vấn đề với chuỗi dài hơn. Tôi muốn viết một phương pháp phi regex để giải quyết vấn đề.
Wiktor Stribiż

2
@ WiktorStribiżew Nếu tôi sao chép chuỗi thử nghiệm vào regexstorm nhiều lần, biến nó thành một chuỗi lớn, tôi nhận được sự khác biệt về hiệu suất, ví dụ như mẫu của bạn 750ms, (.)(?<=(?:.*\1){3})25ms, (.)(?<=(?:\1.*?){2}\1)3ms. Bạn chỉ có thể tự kiểm tra. Bạn dường như là mẫu kém hiệu quả nhất và khó đọc nhất.
bong bóng bobble

Câu trả lời:


8

Dung dịch R không regex. Chia chuỗi. Thay thế các phần tử của vectơ này có rowid> = 3 * bằng '-'. Dán nó lại với nhau.

x <- '111aabbccxccybbzaa1'

xsplit <- strsplit(x, '')[[1]]
xsplit[data.table::rowid(xsplit) >= 3] <- '-'
paste(xsplit, collapse = '')

# [1] "11-aabbccx--y--z---"

* rowid(x)là một vectơ số nguyên với mỗi phần tử biểu thị số lần giá trị từ phần tử tương ứng xđã được nhận ra. Vì vậy, nếu yếu tố cuối cùng x1, và đó là lần thứ tư 1xảy ra x, thì yếu tố cuối cùng rowid(x)4.


4

Bạn có thể dễ dàng thực hiện điều này mà không cần regex:

Xem mã được sử dụng ở đây

s = '111aabbccxccybbzaa1'

for u in set(s):
    for i in [i for i in range(len(s)) if s[i]==u][2:]:
        s = s[:i]+'-'+s[i+1:]

print(s)

Kết quả:

11-aabbccx--y--z---

Cách thức hoạt động:

  1. for u in set(s) lấy danh sách các ký tự duy nhất trong chuỗi: {'c','a','b','y','1','z','x'}
  2. for i in ... các vòng lặp trên các chỉ số mà chúng tôi thu thập trong 3.
  3. [i for i in range(len(s)) if s[i]==u][2:]các vòng lặp trên mỗi ký tự trong chuỗi và kiểm tra xem nó có khớp không u(từ bước 1.), sau đó nó cắt mảng từ phần tử thứ 2 đến hết (bỏ hai phần tử đầu tiên nếu chúng tồn tại)
  4. Đặt chuỗi thành s[:i]+'-'+s[i+1:]- nối chuỗi con lên tới chỉ mục -và sau đó là chuỗi con sau chỉ mục, bỏ qua ký tự gốc một cách hiệu quả.

3

Một tùy chọn với gsubfn

library(gsubfn)
p <- proto(fun = function(this, x) if (count >=3) '-' else x)
for(i in c(0:9, letters)) x <- gsubfn(i, p, x)
x
#[1] "11-aabbccx--y--z---"

dữ liệu

x <- '111aabbccxccybbzaa1'

2

Không có regex python one-liner:

s = "111aabbccxccybbzaa1"

print("".join(char if s.count(char, 0, i) < 2 else "-" for i, char in enumerate(s)))
# ==> "11-aabbccx--y--z---"

Điều này liệt kê thông qua chuỗi, đếm số lần xuất hiện của ký tự hiện tại đằng sau nó và chỉ đặt ký tự nếu đó là một trong 2 ký tự đầu tiên, nếu không thì gạch ngang.


1

Một cách khác để làm điều đó với pandas.

import pandas as pd

s = '111aabbccxccybbzaa1'
# 11-aabbccx--y--z---

df = pd.DataFrame({'Data': list(s)})
df['Count'] = 1
df['cumsum'] = df[['Data', 'Count']].groupby('Data').cumsum()
df.loc[df['cumsum']>=3, 'Data'] = '-'
''.join(df.Data.to_list())

Đầu ra :

11-aabbccx--y--z---

0

Cảm ơn Wiktor Stribiżew , Stefan Pochmannbong bóng bobble . Để hoàn thành, tôi đăng các regexgiải pháp có thể được thảo luận trong các ý kiến;

Điều này chỉ có thể thực hiện được với regex hỗ trợ giao diện chiều rộng vô hạn. Sử dụng mô-đun regex Python PyPi, chúng ta có thể thực hiện các bước sau:

#python 2.7.12

import regex

s = "111aabbccxccybbzaa1"

print(regex.sub(r'(.)(?<=^(?:(?:(?!\1).)*\1){2,}(?:(?!\1).)*\1)', '-', s)) #Wiktor Stribizew
     ## 11-aabbccx--y--z---

print(regex.sub(r'(.)(?<=(.*\1){3})', '-', s)) #Stefan Pochmann
     ## 11-aabbccx--y--z---

print(regex.sub(r'(.)(?<=(?:.*\1){3})', '-', s)) #Wiktor Stribizew
     ## 11-aabbccx--y--z---

print(regex.sub(r'(.)(?<=(?:\1.*?){2}\1)', '-', s)) #bobble bubble
     ## 11-aabbccx--y--z---

Đoạn trích .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.