TLDR: sử dụng theString = theString.replace("\\", "\\\\");
thay thế.
Vấn đề
replaceAll(target, replacement)
sử dụng cú pháp biểu thức chính quy (regex) cho target
và một phần cho replacement
.
Vấn đề là \
ký tự đặc biệt trong regex (nó có thể được sử dụng như \d
để biểu thị chữ số) và trong chuỗi ký tự (nó có thể được sử dụng "\n"
để biểu thị dấu phân tách dòng hoặc \"
để thoát khỏi ký hiệu dấu ngoặc kép thường biểu thị phần cuối của chuỗi ký tự).
Trong cả hai trường hợp này để tạo \
biểu tượng, chúng ta có thể thoát khỏi nó (làm cho nó theo nghĩa đen thay vì ký tự đặc biệt) bằng cách đặt bổ sung \
trước nó (giống như chúng ta thoát "
trong chuỗi ký tự qua \"
).
Vì vậy, để biểu tượng target
đại diện cho regex \
sẽ cần phải giữ \\
, và chuỗi ký tự đại diện cho văn bản như vậy sẽ cần phải trông như thế nào "\\\\"
.
Vì vậy, chúng tôi đã trốn thoát \
hai lần:
- một lần trong regex
\\
- một lần trong chuỗi ký tự
"\\\\"
(mỗi ký tự \
được biểu diễn dưới dạng "\\"
).
Trong trường hợp của replacement
\
cũng là đặc biệt ở đó. Nó cho phép chúng tôi thoát khỏi ký tự đặc biệt khác $
thông qua $x
ký hiệu, cho phép chúng tôi sử dụng một phần dữ liệu được khớp bởi regex và được giữ bằng cách chụp nhóm được lập chỉ mục x
như "012".replaceAll("(\\d)", "$1$1")
sẽ khớp với từng chữ số, đặt nó vào nhóm 1 và $1$1
sẽ thay thế nó bằng hai bản sao của nó (nó sẽ nhân bản nó) dẫn đến "001122"
.
Vì vậy, một lần nữa, để replacement
đại diện cho \
nghĩa đen, chúng ta cần phải loại bỏ nó bằng cách bổ sung \
có nghĩa là:
- thay thế phải giữ hai ký tự gạch chéo ngược
\\
- và chuỗi ký tự thể hiện
\\
trông giống như"\\\\"
NHƯNG vì chúng ta muốn replacement
giữ hai dấu gạch chéo ngược, chúng ta sẽ cần "\\\\\\\\"
(mỗi dấu gạch chéo ngược được \
biểu thị bằng một "\\\\"
).
Vì vậy, phiên bản với replaceAll
có thể trông giống như
replaceAll("\\\\", "\\\\\\\\");
Cách dễ dàng hơn
Để làm cho cuộc sống dễ dàng hơn, Java cung cấp các công cụ để tự động thoát văn bản vào target
và replacement
các phần. Vì vậy, bây giờ chúng ta có thể chỉ tập trung vào chuỗi và quên cú pháp regex:
replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))
trong trường hợp của chúng ta có thể trông như thế nào
replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))
Thậm chí còn tốt hơn
Nếu chúng ta không thực sự cần hỗ trợ cú pháp regex thì không nên liên quan replaceAll
gì cả. Thay vào đó, hãy sử dụng replace
. Cả hai phương thức sẽ thay thế tất cả các target
s, nhưng replace
không liên quan đến cú pháp regex. Vì vậy, bạn có thể chỉ cần viết
theString = theString.replace("\\", "\\\\");