Próbuję przekonwertować String
\something\
go na String
\\something\\
używanie replaceAll
, ale wciąż otrzymuję wszelkiego rodzaju błędy. Myślałem, że to rozwiązanie:
theString.replaceAll("\\", "\\\\");
Ale to daje poniższy wyjątek:
java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
źródło
String#replaceAll()
mimo wszystko chcesz użyć , możesz zacytować ciąg zastępujący za pomocą Matcher # quoteReplacement () :theString.replaceAll("\\", Matcher.quoteReplacement("\\\\"));
Aby uniknąć tego rodzaju problemów, możesz użyć
replace
(który pobiera zwykły ciąg) zamiastreplaceAll
(który przyjmuje wyrażenie regularne). Nadal będziesz musiał unikać odwrotnych ukośników, ale nie w sposób dziki wymagany w wyrażeniach regularnych.źródło
TLDR: użyj
theString = theString.replace("\\", "\\\\");
zamiast tego.Problem
replaceAll(target, replacement)
używa składni wyrażeń regularnych (regex) dlatarget
i częściowo dlareplacement
.Problem polega na tym, że
\
jest to znak specjalny w wyrażeniu regularnym (może być używany tak jak\d
do reprezentacji cyfry) i w literale String (może być używany jak"\n"
do reprezentowania separatora linii lub\"
do ucieczki przed symbolem podwójnego cudzysłowu, który normalnie oznaczałby koniec literału ciągu).W obu tych przypadkach, aby stworzyć
\
symbol, możemy przed nim uciec (uczynić go dosłownym zamiast znaku specjalnego), umieszczając\
przed nim dodatkowe (tak jak"
w przypadku literałów ciągu przez\"
).Tak więc
target
regex reprezentujący\
symbol będzie musiał się trzymać\\
, a literał łańcuchowy reprezentujący taki tekst będzie musiał wyglądać"\\\\"
.Więc uciekliśmy
\
dwa razy:\\
"\\\\"
(każdy\
jest reprezentowany jako"\\"
).W przypadku
replacement
\
jest też tam wyjątkowy. Pozwala nam uciec przed innym znakiem specjalnym,$
który za pomocą$x
notacji pozwala nam użyć części danych dopasowanych przez wyrażenie regularne i przechowywanych przez grupę przechwytywania indeksowaną takx
, jak"012".replaceAll("(\\d)", "$1$1")
będzie pasowała do każdej cyfry, umieści ją w grupie przechwytywania 1 i$1$1
zastąpi ją dwoma kopiami (zduplikuje to), w wyniku czego"001122"
.Więc znowu, aby
replacement
reprezentować\
dosłownie, musimy uciec od tego dodatkowym,\
co oznacza, że:\\
\\
wygląd"\\\\"
ALE ponieważ chcemy
replacement
trzymać dwa ukośniki odwrotne, których będziemy potrzebować"\\\\\\\\"
(każdy\
reprezentowany przez jeden"\\\\"
).Więc wersja z
replaceAll
może wyglądaćŁatwiejszy sposób
Aby ułatwić życie, Java udostępnia narzędzia do automatycznego wprowadzania tekstu do
target
ireplacement
części. Więc teraz możemy skupić się tylko na łańcuchach i zapomnieć o składni regex:co w naszym przypadku może wyglądać
Nawet lepiej
Jeśli naprawdę nie potrzebujemy obsługi składni wyrażeń regularnych, nie angażujmy się
replaceAll
w ogóle. Zamiast tego użyjmyreplace
. Obie metody zastąpią wszystkietarget
s, alereplace
nie obejmują składni wyrażeń regularnych. Możesz więc po prostu napisaćźródło
Będziesz musiał pominąć (uciekający) ukośnik odwrotny w pierwszym argumencie, ponieważ jest to wyrażenie regularne. Zastąpienie (drugi argument - zobacz Matcher # replaceAll (String) ) również ma specjalne znaczenie odwrotnych ukośników, więc będziesz musiał zamienić je na:
źródło
Tak ... zanim kompilator regex zobaczy wzorzec, który mu podałeś, widzi tylko jeden ukośnik odwrotny (ponieważ lekser Javy zamienił podwójny backwhack na pojedynczy). Trzeba wymienić
"\\\\"
z"\\\\"
wierzyć lub nie! Java naprawdę potrzebuje dobrej składni nieprzetworzonych łańcuchów.źródło