TLDR: використовувати theString = theString.replace("\\", "\\\\");
замість цього.
Проблема
replaceAll(target, replacement)
використовує синтаксис регулярного вираження (регулярного вираження) для target
і частково для replacement
.
Проблема полягає в тому, що \
це спеціальний символ у регулярному виразі (його можна використовувати як \d
представлення цифри) та в рядковому літералі (він може використовуватися як "\n"
представити роздільник рядків або \"
уникнути подвійного символу цитати, який зазвичай би представляв кінець рядкового літералу).
В обох цих випадках для створення \
символу ми можемо уникнути його (зробимо його буквальним замість спеціального символу), поставивши \
перед ним додаткові (як, наприклад, ми втечемо "
в рядкові літерали через \"
).
Таким чином, для target
регулярного вираження \
символу, що символізує, потрібно виконати \\
, а рядковий буквальний текст, що представляє такий текст, повинен мати вигляд "\\\\"
.
Тож ми втекли \
двічі:
- один раз у регулярному вираженні
\\
- один раз у String literal
"\\\\"
(кожен \
представлений як "\\"
).
У випадку replacement
\
також є спеціальним. Це дозволяє нам уникнути іншого спеціального символу, $
який за допомогою $x
позначень дозволяє використовувати частину даних, зіставлених за допомогою регулярного виразів та утримуваних, захоплюючи групу з індексом, як x
, як і "012".replaceAll("(\\d)", "$1$1")
буде відповідати кожній цифрі, помістити її в групу захоплення 1 і $1$1
замінить її на дві її копії (це буде дублювати), в результаті чого "001122"
.
Отже, знову для того, щоб replacement
представляти \
буквальне, нам потрібно уникнути його з додатковими, \
що означає:
- заміна повинна містити два символи зворотної косої риски
\\
- і Stral literal, який представляє,
\\
виглядає так"\\\\"
АЛЕ, оскільки ми хочемо replacement
провести два нахили, які нам знадобляться "\\\\\\\\"
(кожен \
представлений одним "\\\\"
).
Так replaceAll
може виглядати версія з
replaceAll("\\\\", "\\\\\\\\");
Найпростіший спосіб
Щоб полегшити життя, Java надає інструменти для автоматичного переходу тексту на частини target
та їх replacement
частини. Тож тепер ми можемо зосередитись лише на рядках та забути про синтаксис регулярних виразів:
replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))
що в нашому випадку може виглядати так
replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))
Навіть краще
Якщо нам дійсно не потрібна підтримка синтаксису регулярних виразів, давайте взагалі не залучатись replaceAll
. Натомість дозволяє використовувати replace
. Обидва методи замінять усі target
s, але replace
не включають синтаксис регулярного виразів. Так ви могли просто написати
theString = theString.replace("\\", "\\\\");