Java มีวิธีในตัวเพื่อหลีกเลี่ยงข้อความที่กำหนดเองเพื่อให้สามารถรวมไว้ในนิพจน์ทั่วไปได้หรือไม่? ตัวอย่างเช่นหากผู้ใช้ของฉันป้อน "$ 5" ฉันต้องการจับคู่นั้นแทนที่จะเป็น "5" หลังจากสิ้นสุดการป้อนข้อมูล
Java มีวิธีในตัวเพื่อหลีกเลี่ยงข้อความที่กำหนดเองเพื่อให้สามารถรวมไว้ในนิพจน์ทั่วไปได้หรือไม่? ตัวอย่างเช่นหากผู้ใช้ของฉันป้อน "$ 5" ฉันต้องการจับคู่นั้นแทนที่จะเป็น "5" หลังจากสิ้นสุดการป้อนข้อมูล
คำตอบ:
ตั้งแต่Java 1.5 ใช่ :
Pattern.quote("$5");
"mouse".toUpperCase().replaceAll("OUS","ic")
MicE
คุณ would't คาดหวังว่ามันจะกลับมาMICE
เพราะคุณไม่ได้นำไปใช้ในtoUpperCase()
ic
ในตัวอย่างของฉันquote()
ถูกนำไปใช้กับตัว.*
แทรกด้วยreplaceAll()
เช่นกัน คุณต้องทำอย่างอื่นบางทีอาจใช้.replaceAll("*","\\E.*\\Q")
งานได้
*.wav
เป็นรูปแบบ regex \*\.wav
และ replaceAll จะกลายเป็น\.*\.wav
หมายความว่ามันจะ .wav
ไฟล์การแข่งขันที่มีชื่อประกอบด้วยจำนวนโดยพลการของงวดตามมาด้วย คุณน่าจะต้องการreplaceAll("\\*", ".*")
ถ้าพวกเขาไปด้วยการใช้งานที่เปราะบางมากขึ้นซึ่งขึ้นอยู่กับการจดจำ charachters ที่ใช้งานได้ทั้งหมดที่เป็นไปได้และหนีพวกเขาทีละคน ... นั่นจะง่ายกว่านี้ไหม?
ความแตกต่างระหว่างPattern.quote
และMatcher.quoteReplacement
ไม่ชัดเจนกับฉันก่อนที่ฉันจะเห็นตัวอย่างต่อไปนี้
s.replaceFirst(Pattern.quote("text to replace"),
Matcher.quoteReplacement("replacement text"));
Pattern.quote
แทนที่อักขระพิเศษในสตริงการค้นหาของ regex เช่น | + () ฯลฯ และMatcher.quoteReplacement
แทนที่อักขระพิเศษในสตริงการแทนที่เช่น \ 1 สำหรับการอ้างอิงย้อนกลับ
quoteReplacement
ใส่ใจเพียงประมาณสองสัญลักษณ์$
และ\
ที่สามารถยกตัวอย่างเช่นจะใช้ในสตริงทดแทน backreferences หรือ$1
\1
ดังนั้นจึงต้องไม่ใช้เพื่อหลบหนี / อ้างถึง regex
$Group$
สัญลักษณ์เป็นพิเศษทั้งในรูปแบบและในการเปลี่ยน:T$UYO$HI
$
"$Group$ Members".replaceFirst(Pattern.quote("$Group$"), Matcher.quoteReplacement("T$UYO$HI"))
อาจตอบสนองช้าเกินไป แต่คุณสามารถใช้Pattern.LITERAL
ซึ่งจะละเว้นอักขระพิเศษทั้งหมดในขณะที่จัดรูปแบบ:
Pattern.compile(textToFormat, Pattern.LITERAL);
Pattern.CASE_INSENSITIVE
\Q$5\E
ผมคิดว่าสิ่งที่คุณหลังจากเป็น ดูเพิ่มเติมที่Pattern.quote(s)
แนะนำใน Java5
ดูรายละเอียดรูปแบบ javadoc
ก่อนอื่นถ้า
มันจะไม่ใส่ 1 ในตอนท้าย มันจะดูที่ regex การค้นหาสำหรับกลุ่มการจับคู่แรกและย่อยที่นั่นนั่นคือสิ่งที่ $ 1, $ 2 หรือ $ 3 หมายถึงในข้อความแทนที่: กลุ่มการจับคู่จากรูปแบบการค้นหา
ฉันมักจะเสียบสายข้อความยาว ๆ เข้าไปในไฟล์. properties แล้วสร้างหัวเรื่องอีเมลและเนื้อหาจากสิ่งเหล่านั้น แน่นอนว่านี่เป็นวิธีการเริ่มต้นในการทำ i18n ใน Spring Framework ฉันใส่แท็ก XML เป็นตัวยึดตำแหน่งลงในสตริงและฉันใช้ replaceAll () เพื่อแทนที่แท็ก XML ด้วยค่าที่รันไทม์
ฉันพบปัญหาที่ผู้ใช้ป้อนตัวเลขดอลลาร์และเซ็นต์ด้วยเครื่องหมายดอลลาร์ replaceAll () สำลักกับดังต่อไปนี้ปรากฏขึ้นใน stracktrace:
java.lang.IndexOutOfBoundsException: No group 3
at java.util.regex.Matcher.start(Matcher.java:374)
at java.util.regex.Matcher.appendReplacement(Matcher.java:748)
at java.util.regex.Matcher.replaceAll(Matcher.java:823)
at java.lang.String.replaceAll(String.java:2201)
ในกรณีนี้ผู้ใช้ป้อน "$ 3" ที่ไหนสักแห่งในการป้อนข้อมูลของพวกเขาและ replaceAll () ไปดูใน regex การค้นหาสำหรับกลุ่มการจับคู่ที่สามไม่พบหนึ่งและ puked
ได้รับ:
// "msg" is a string from a .properties file, containing "<userInput />" among other tags
// "userInput" is a String containing the user's input
การแทนที่
msg = msg.replaceAll("<userInput \\/>", userInput);
กับ
msg = msg.replaceAll("<userInput \\/>", Matcher.quoteReplacement(userInput));
แก้ไขปัญหา ผู้ใช้สามารถใส่อักขระทุกชนิดรวมถึงเครื่องหมายดอลลาร์โดยไม่มีปัญหา มันทำงานอย่างที่คุณคาดหวัง
มีรูปแบบการป้องกันคุณสามารถแทนที่สัญลักษณ์ทั้งหมดด้วย "\\\\" ยกเว้นตัวเลขและตัวอักษร และหลังจากนั้นคุณสามารถใส่รูปแบบที่มีการป้องกันสัญลักษณ์พิเศษของคุณเพื่อทำให้รูปแบบนี้ทำงานได้ไม่เหมือนกับข้อความที่ยกมาโง่ แต่ชอบเสื้อคลุม แต่เป็นของคุณเอง ไม่มีสัญลักษณ์พิเศษของผู้ใช้
public class Test {
public static void main(String[] args) {
String str = "y z (111)";
String p1 = "x x (111)";
String p2 = ".* .* \\(111\\)";
p1 = escapeRE(p1);
p1 = p1.replace("x", ".*");
System.out.println( p1 + "-->" + str.matches(p1) );
//.*\ .*\ \(111\)-->true
System.out.println( p2 + "-->" + str.matches(p2) );
//.* .* \(111\)-->true
}
public static String escapeRE(String str) {
//Pattern escaper = Pattern.compile("([^a-zA-z0-9])");
//return escaper.matcher(str).replaceAll("\\\\$1");
return str.replaceAll("([^a-zA-Z0-9])", "\\\\$1");
}
}
Pattern.quote ("blabla") ทำงานได้ดี
Pattern.quote () ทำงานได้ดี มันล้อมรอบประโยคด้วยตัวละคร " \ Q " และ " \ E " และถ้ามันหลบหนี "\ Q" และ "\ E" อย่างไรก็ตามหากคุณจำเป็นต้องใช้การแสดงออกปกติอย่างแท้จริง (หรือการหลบหนีที่กำหนดเอง) คุณสามารถใช้รหัสนี้:
String someText = "Some/s/wText*/,**";
System.out.println(someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));
วิธีนี้จะคืนค่า: บาง / \ s / wText * / \, **
รหัสสำหรับตัวอย่างและการทดสอบ:
String someText = "Some\\E/s/wText*/,**";
System.out.println("Pattern.quote: "+ Pattern.quote(someText));
System.out.println("Full escape: "+someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));
ใช้สัญลักษณ์ ^ (การปฏิเสธ) เพื่อจับคู่สิ่งที่ไม่ได้อยู่ในกลุ่มอักขระ
นี่คือลิงค์ไปยังนิพจน์ปกติ
นี่คือข้อมูลภาพเกี่ยวกับการปฏิเสธ:
\Q
\E
สิ่งนี้อาจนำไปสู่ผลลัพธ์ที่ไม่คาดคิดเช่นPattern.quote("*.wav").replaceAll("*",".*")
จะส่งผล\Q.*.wav\E
และไม่.*\.wav
เป็นไปตามที่คุณคาดหวัง