डुप्लिकेट किए गए वर्णों को मिलाएं और निकालें: कई (3+) गैर-लगातार घटनाओं को बदलें


9

मैं एक ऐसे regexपैटर्न की तलाश में हूं जो प्रत्येक चरित्र की तीसरी, चौथी, ... घटना से मेल खाएगा। स्पष्टीकरण के लिए नीचे देखें:

उदाहरण के लिए मेरे पास निम्नलिखित स्ट्रिंग है:

111aabbccxccybbzaa1

मैं दूसरी घटना के बाद सभी डुप्लिकेट किए गए पात्रों को बदलना चाहता हूं। उत्पादन होगा:

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

कुछ रेगेक्स पैटर्न जो मैंने अब तक आजमाए:

निम्नलिखित रेगेक्स का उपयोग करके मैं प्रत्येक वर्ण की अंतिम घटना पा सकता हूं:

(.)(?=.*\1)

या इस एक का उपयोग करके मैं इसे लगातार डुप्लिकेट के लिए कर सकता हूं लेकिन किसी डुप्लिकेट के लिए नहीं:

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


1
रेगेक्स के साथ आप किस रेगेक्स इंजन का उपयोग करने की योजना बना रहे हैं?
विकिटोर स्ट्राइब्यू

1
आप केवल एक रेगेक्स के साथ कर सकते हैं जो अनंत चौड़ाई लुकअप का समर्थन करता है, इसलिए आपका एकमात्र विकल्प पायथन पायपी रेगेक्स मॉड्यूल है। (.)(?<=^(?:(?:(?!\1).)*\1){2,}(?:(?!\1).)*\1)रेगेक्स के साथ इसका उपयोग करें । डेमो
विकटोरिया स्ट्राइब्यू

3
@ WiktorStribiżew क्या इससे बेहतर है (.)(?<=(.*\1){3})?
स्टीफन पोचमैन 21

2
@StefanPochmann ठीक है, (.)(?<=(?:.*\1){3})काम भी करेंगे, लेकिन ये सभी अच्छे नहीं हैं क्योंकि अत्यधिक बैकट्रैकिंग लंबे समय तक तार के साथ मुद्दों का कारण बन सकता है। मैं समस्या को हल करने के लिए एक गैर-रेगेक्स विधि लिखूंगा।
विकटोरिया स्ट्रीब्यू

2
@ WiktorStribiżew यदि मैं कई बार रीस्ट्रक्सस्टॉर्म में टेस्टिंगस्ट्रिंग की नकल करता हूं, तो यह एक विशाल स्ट्रिंग बनाता है, मुझे प्रदर्शन अंतर मिलता है जैसे आपका पैटर्न 750ms, (.)(?<=(?:.*\1){3})25ms, (.)(?<=(?:\1.*?){2}\1)3ms। आप बस खुद को परख सकते हैं। तुम्हारा कम से कम कुशल पैटर्न लगता है और यह पढ़ने में सबसे कठिन है।
बुलबुला

जवाबों:


9

गैर-रेगेक्स आर समाधान। स्प्लिट स्ट्रिंग। इस वेक्टर के तत्वों को प्रतिस्थापित करें> = 3 * के साथ '-'। इसे वापस एक साथ चिपकाएं।

x <- '111aabbccxccybbzaa1'

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

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

* rowid(x)एक पूर्णांक वेक्टर है जिसमें प्रत्येक तत्व का प्रतिनिधित्व किया जाता है, जो संबंधित तत्व के मूल्य से कई गुना अधिक है x। इसलिए यदि अंतिम तत्व xहै 1, और वह चौथी बार 1है x, तो अंतिम तत्व rowid(x)है 4


4

आप इसे आसानी से रेगेक्स के बिना पूरा कर सकते हैं:

उपयोग में कोड देखें

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)

परिणाम:

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

यह कैसे काम करता है:

  1. for u in set(s) स्ट्रिंग में अद्वितीय वर्णों की एक सूची मिलती है: {'c','a','b','y','1','z','x'}
  2. for i in ... हम 3 में इकट्ठा होने वाले सूचकांकों पर लूप करते हैं।
  3. [i for i in range(len(s)) if s[i]==u][2:]स्ट्रिंग में प्रत्येक वर्ण पर लूप होता है और जांचता है कि क्या यह मेल खाता है u(चरण 1 से), तो यह 2 तत्व से अंत तक सरणी को स्लाइस करता है (यदि वे मौजूद हैं तो पहले दो तत्वों को छोड़ते हैं)
  4. स्ट्रिंग को s[:i]+'-'+s[i+1:]- के साथ अनुक्रमणिका तक प्रतिस्थापित करें -और फिर अनुक्रमणिका के बाद प्रतिस्थापन को प्रभावी ढंग से मूल चरित्र को छोड़ते हुए।

3

के साथ एक विकल्प 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---"

डेटा

x <- '111aabbccxccybbzaa1'

2

रेगेक्स पायथन वन-लाइनर:

s = "111aabbccxccybbzaa1"

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

यह स्ट्रिंग के माध्यम से गणना करता है, इसके पीछे वर्तमान चरित्र की घटनाओं की गिनती करता है और केवल चरित्र को डालता है यदि यह पहले 2 में से एक है, अन्यथा पानी का छींटा।


1

इसके साथ एक और तरीका है 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())

आउटपुट :

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

0

विकटोरियो स्ट्रीब्यू , स्टीफन पोचमैन , और बबल बबल के लिए धन्यवाद । पूर्णता के लिए, मैं regexटिप्पणियों में चर्चा किए गए संभावित समाधान पोस्ट कर रहा हूं ;

यह केवल एक रेगेक्स के साथ उल्लेखनीय है जो अनंत चौड़ाई लुकबाइंड का समर्थन करता है। पायथन PyPi रेगेक्स मॉड्यूल का उपयोग करके हम अनुसरण कर सकते हैं:

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

स्निपेट

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.