Yinelenen karakterleri eşleştirme ve kaldırma: Birden fazla (3+) ardışık olmayan örneği değiştirin


9

regexHer karakterin üçüncü, dördüncü, oluşumu ile eşleşecek bir model arıyorum . Açıklama için aşağıya bakın:

Örneğin ben aşağıdaki dize var:

111aabbccxccybbzaa1

İkinci olaydan sonra tüm yinelenen karakterleri değiştirmek istiyorum. Çıktı şöyle olacaktır:

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

Şimdiye kadar denediğim bazı regex kalıpları:

Aşağıdaki normal ifadeyi kullanarak her karakterin son tekrarlamasını bulabilirim:

(.)(?=.*\1)

Ya da bunu kullanarak ardışık kopyalar için yapabilirim ama herhangi bir kopya için değil:

([a-zA-Z1-9])\1{2,}


1
Normal regex ile hangi regex motorunu kullanmayı planlıyorsunuz?
Wiktor Stribiżew

1
Bunu sadece sonsuz genişlikli gözbebekini destekleyen bir normal ifade ile yapabilirsiniz, bu nedenle tek seçeneğiniz Python PyPi normal ifade modülüdür. (.)(?<=^(?:(?:(?!\1).)*\1){2,}(?:(?!\1).)*\1)Normal ifade ile kullanın . Demo .
Wiktor Stribiżew

3
@ WiktorStribiżew Bundan daha mı iyi (.)(?<=(.*\1){3})?
Stefan Pochmann

2
@StefanPochmann (.)(?<=(?:.*\1){3})İşi de yapacak, ancak bunların hepsi iyi değil çünkü aşırı geri izleme daha uzun dizelerle ilgili sorunlara neden olabilir. Sorunu çözmek için regex olmayan bir yöntem yazmayı tercih ederim.
Wiktor Stribiżew

2
@ WiktorStribiżew Test dizesini birkaç kez regexstorm'a kopyalarsam, büyük bir dize haline getirirsem, örneğin 750ms, (.)(?<=(?:.*\1){3})25ms, 3ms gibi performans farkı elde ederim (.)(?<=(?:\1.*?){2}\1). Kendinizi test edebilirsiniz. Sizinki en az verimli desen gibi görünüyor ve okumak en zor.
bobble kabarcık

Yanıtlar:


9

Normal olmayan R çözeltisi. Bölünmüş dize. Bu vektörün rowid> = 3 * olan elemanlarını değiştirin '-'. Birlikte yapıştırın.

x <- '111aabbccxccybbzaa1'

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

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

* rowid(x), her elemanın karşılık gelen elemanından değerin gerçekleşme sayısını temsil eden bir tamsayı vektörüdür x. Yani eğer son elemanı xise 1ve bu dördüncü kez 1meydana gelmişse x, son elemanı da rowid(x)olur 4.


4

Normal ifade olmadan bunu kolayca yapabilirsiniz:

Kullanılan koda bakın

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)

Sonuç:

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

Bu nasıl çalışır:

  1. for u in set(s) dizede benzersiz karakterlerin bir listesini alır: {'c','a','b','y','1','z','x'}
  2. for i in ... 3'te topladığımız endekslerin üzerinden geçer.
  3. [i for i in range(len(s)) if s[i]==u][2:]dizedeki her karakterin üzerine döner ve eşleşip eşleşmediğini kontrol eder u(1. adımdan), ardından diziyi 2. öğeden sonuna kadar dilimler (varsa ilk iki öğeyi bırakarak)
  4. Dize ayarlayın s[:i]+'-'+s[i+1:]BİRLEŞTİR ile endekse alt dize - -etkin bir orijinal karakter atlayarak, dizin sonra sonra ve alt dize.

3

İle bir seçenek 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---"

veri

x <- '111aabbccxccybbzaa1'

2

Normal ifade python tek astarı yok:

s = "111aabbccxccybbzaa1"

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

Bu, dize boyunca numaralandırılır, arkasındaki geçerli karakterin oluşumlarını sayar ve karakteri yalnızca ilk 2'den biri ise, aksi takdirde tire ekler.


1

Bunu yapmanın başka bir yolu 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())

Çıktı :

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

0

Sayesinde Wiktor Stribiżew , Stefan POCHMANN ve Bobble kabarcık . Tamamlama uğruna regex, yorumlarda tartışılan olası çözümleri gönderiyorum ;

Bu sadece sonsuz genişlikli gözbebekini destekleyen bir normal ifade ile yapılabilir. Python PyPi regex modülünü kullanarak aşağıdakileri yapabiliriz:

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

Snippet .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.