web-dev-qa-db-ja.com

重複する文字を一致させて削除する:複数(3+)の連続しない出現箇所を置き換えます

各文字の3番目、4番目、...の出現に一致するregexパターンを探しています。明確にするために以下を見てください:

たとえば、次の文字列があります。

111aabbccxccybbzaa1

2回目以降の重複文字をすべて置換したい。出力は次のようになります。

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

これまでに試したいくつかの正規表現パターン:

次の正規表現を使用して、各文字の最後の出現を見つけることができます: (.)(?=.*\1)

または、これを使用して、連続する重複にはそれを行うことができますが、重複にはできません: ([a-zA-Z1-9])\1{2,}

9
M--

非正規表現Rソリューション。文字列を分割します。 ROWID> = 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_であり、xで_1_が4回発生した場合、rowid(x)の最後の要素は_4_です。

8
IceCreamToucan

これは正規表現なしで簡単に実現できます。

ここで使用中のコードを参照

_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番目の要素から最後まで配列をスライスします(最初の2つの要素を削除します)。それらが存在する場合)
  4. 文字列を_s[:i]+'-'+s[i+1:]_に設定します-インデックスまでの部分文字列を_-_と連結し、次にインデックスの後の部分文字列を連結して、元の文字を効果的に省略します。
4
ctwheels

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'
3
akrun

正規表現なし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---"

これは文字列を列挙し、その後ろにある現在の文字の出現回数を数え、最初の2文字の1つである場合にのみ文字を置きます。それ以外の場合はダッシュです。

2
ParkerD

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---
1
CypherX

おかげでWiktorStribiżewStefan Pochmann、および泡バブル。完了のために、コメントで説明されている可能なregexソリューションを投稿しています。

これは、無限幅の後読みをサポートする正規表現でのみ実行できます。 Python PyPi regexモジュールを使用すると、次のことができます。

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

スニペット

0
M--