2014-12-11 8 views
7

mam ten wymóg - dla ciągu znaków, takich jak przedstawione poniżejwymienić kilka grup chwytania metodą regularne z Java

8This8 is &reallly& a #test# of %repl%acing% %mul%tiple 9matched9 9pairs 

chciałbym odizolować dopasowane granic słowa (gdzie pasujące pary wynosi 8 lub & lub%) i odpowiednio będzie powodować w następujący

This is really a test of repl%acing %mul%tiple matched 9pairs 

Ta lista znaków, który jest wykorzystywany dla pary może się zmieniać np 8,9,%, # itd. I tylko słowa pasujące do początku i końca z każdym typem zostaną pozbawione tych znaków, z tym samym znakiem osadzonym w słowie pozostającym tam, gdzie jest.

Korzystanie Java mogę zrobić wzór jako \\b8([^\\s]*)8\\b i wymianę jako $ 1, aby uchwycić i zastąpić wszystkie wystąpienia 8 ... 8, ale w jaki sposób to zrobić dla wszystkich rodzajów par?

mogę zapewnić wzór takich jak \\b8([^\\s]*)8\\b|\\b9([^\\s]*)9\\b .. i tak dalej, które pasują do wszystkich rodzajów pasujących par * 8,9, ..), ale w jaki sposób mogę określić „zmienna” grupę wymiana -

na przykład jeśli mecz wynosi 9 ... 9, zamiennik powinien wynosić 2 $.

Mogę oczywiście przeprowadzić to przez wiele z nich, każdy zastępując określony typ pary, ale zastanawiam się, czy istnieje bardziej elegancki sposób.

Czy istnieje zupełnie inny sposób podejścia do tego problemu?

Dzięki.

Odpowiedz

3

Można użyć poniższego wyrażenia regularnego, a następnie zastąpić dopasowane znaków przez bohaterów występujących wewnątrz indeksu grupy 2.

(?<!\S)(\S)(\S+)\1(?=\s|$) 

LUB

(?<!\S)(\S)(\S*)\1(?=\s|$) 

regex Java byłoby

(?<!\\S)(\\S)(\\S+)\\1(?=\\s|$) 

DEMO

String s1 = "8This8 is &reallly& a #test# of %repl%acing% %mul%tiple 9matched9 9pairs"; 
System.out.println(s1.replaceAll("(?<!\\S)(\\S)(\\S+)\\1(?=\\s|$)", "$2")); 

wyjściowa:

This is reallly a test of repl%acing %mul%tiple matched 9pairs 

Objaśnienie:

  • (?<!\\S) Negative lookbehind, twierdzi, że mecz nie będzie poprzedzony ma charakteru przestrzeni.
  • (\\S) Przechwytuje pierwsze charakter non-przestrzeń i zapisuje go do indeksu grupy 1.
  • (\\S+) Przechwytuje jeden lub więcej znaków non-space.
  • Odnosi się do postaci wewnątrz pierwszej przechwyconej grupy.
  • (?=\\s|$) Po dopasowaniu musi następować spacja lub koniec zakotwiczenia linii.
  • Zapewnia to, że pierwszy znak i ostatni znak ciągu muszą być takie same. Jeśli tak, to zastępuje cały mecz przez znaki, które są obecne wewnątrz indeksu grupy 2.

w tym konkretnym przypadku można zmodyfikować powyższy regex jak

String s1 = "8This8 is &reallly& a #test# of %repl%acing% %mul%tiple 9matched9 9pairs"; 
System.out.println(s1.replaceAll("(?<!\\S)([89&#%])(\\S+)\\1(?=\\s|$)", "$2")); 

DEMO

+1

Dzięki. Korzystanie z back odniesienia i przechwytywania grup do 2, zgodnie z sugestią Ciebie i innej osoby, zdaje się ją przybić. Używam następujących (? ssen

+0

@Ssen dokładnie to masz. Znacznie bardziej zredukowany jeden (?

1
(?<![a-zA-Z])[8&#%9](?=[a-zA-Z])([^\s]*?)(?<=[a-zA-Z])[8&#%9](?![a-zA-Z]) 

Wypróbuj. Wypróbuj z $1 lub \1. Zobacz wersję demo.

https://regex101.com/r/qB0jV1/15

(?<![a-zA-Z])[^a-zA-Z](?=[a-zA-Z])([^\s]*?)(?<=[a-zA-Z])[^a-zA-Z](?![a-zA-Z]) 

Użyj tego, jeśli masz wiele ograniczników.

Powiązane problemy