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("\\", "\\\\");