중복 문자 일치 및 제거 : 비 연속적으로 여러 번 발생하는 대체


9

나는 regex각 문자의 세 번째, 네 번째 ... 발생과 일치 하는 패턴을 찾고 있습니다. 설명을 위해 아래를보십시오.

예를 들어 다음 문자열이 있습니다.

111aabbccxccybbzaa1

두 번째 발생 후 모든 복제 된 문자를 바꾸고 싶습니다. 출력은 다음과 같습니다.

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

내가 지금까지 시도한 일부 정규식 패턴 :

다음 정규식을 사용하여 각 문자의 마지막 항목을 찾을 수 있습니다. (.)(?=.*\1)

또는이 것을 사용하면 연속 복제에 대해서는 할 수 있지만 중복에 대해서는 할 수 없습니다. ([a-zA-Z1-9])\1{2,}


1
정규식에 어떤 정규식 엔진을 사용할 계획입니까?
Wiktor Stribiżew

1
무한 너비 lookbehind를 지원하는 정규식으로 만 그렇게 할 수 있으므로 유일한 옵션은 Python PyPi 정규식 모듈입니다. (.)(?<=^(?:(?:(?!\1).)*\1){2,}(?:(?!\1).)*\1)정규식 과 함께 사용하십시오 . 데모 .
Wiktor Stribiżew

3
@ WiktorStribiżew보다 나은가요 (.)(?<=(.*\1){3})?
Stefan Pochmann

2
@StefanPochmann 글쎄, 그 일도 (.)(?<=(?:.*\1){3})할 것이지만 과도한 역 추적은 긴 문자열에 문제를 일으킬 수 있기 때문에 이것들 모두는 좋지 않습니다. 오히려 문제를 해결하기 위해 정규식이 아닌 방법을 작성하고 싶습니다.
Wiktor Stribiżew

2
@ WiktorStribiżew 테스트 문자열을 regexstorm에 여러 번 복사하여 큰 문자열로 만들면 패턴 750ms, (.)(?<=(?:.*\1){3})25ms, (.)(?<=(?:\1.*?){2}\1)3ms 와 같은 성능 차이가 발생합니다 . 당신은 자신을 테스트 할 수 있습니다. 가장 효율적인 패턴으로 보이며 읽기가 가장 어렵습니다.
버블 버블

답변:


8

비정규 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이 실현 된 횟수를 나타내는 정수 벡터입니다 . 따라서의 마지막 요소 x1에서이고 네 번째 시간 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:]문자열의 각 문자를 반복하고 u1 단계부터 일치 하는지 확인한 다음 배열을 두 번째 요소에서 끝으로 슬라이스합니다 (처음 두 요소가있는 경우)
  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

정규식 파이썬 1 라이너 없음 :

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

Wiktor Stribiżew , Stefan Pochmann보블 버블 덕분 입니다. 완성을 위해 게시 가능합니다regex 의견에 논의 된 해결책을 .

이것은 무한 너비 lookbehind를 지원하는 정규식에서만 가능합니다. Python 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---

발췌문 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.