บทนำ
การนับจำนวนคำที่เกิดขึ้นในสตริงเป็นงานที่ค่อนข้างง่าย แต่มีหลายวิธีในการทำเช่นนั้น คุณต้องคำนึงถึงประสิทธิภาพของวิธีการด้วย เนื่องจากโดยปกติคุณต้องการใช้เครื่องมืออัตโนมัติเมื่อคุณไม่ต้องการใช้แรงงานคน เช่น เมื่อพื้นที่ค้นหามีขนาดใหญ่
ในคู่มือนี้ คุณจะได้เรียนรู้วิธีนับจำนวนคำที่เกิดขึ้นในสตริงใน Java:
String searchText = "Your body may be chrome, but the heart never changes. It wants what it wants.";
String targetWord = "wants";
เราจะค้นหาจำนวนครั้งของ targetWord
โดยใช้ String.split()
, Collections.frequency()
และนิพจน์ทั่วไป
นับคำที่เกิดขึ้นในสตริงด้วย สตริง.split()
วิธีที่ง่ายที่สุดในการนับการเกิดขึ้นของคำเป้าหมายในสตริงคือการแยกสตริงในแต่ละคำ และวนซ้ำในอาร์เรย์ โดยเพิ่มค่า a wordCount
ในแต่ละนัด โปรดทราบว่าเมื่อคำมีเครื่องหมายวรรคตอนอยู่รอบๆ เช่น wants.
ที่ส่วนท้ายของประโยค – การแบ่งระดับคำอย่างง่ายจะถือว่าถูกต้อง wants
และ wants.
เป็นคำแยก!
เพื่อแก้ปัญหานี้ คุณสามารถลบเครื่องหมายวรรคตอนทั้งหมดออกจากประโยคได้อย่างง่ายดาย ก่อน แยกมัน:
String[] words = searchText.replaceAll("p{Punct}", "").split(" ");
int wordCount = 0;
for (int i=0; i < words.length; i++)
if (words[i].equals(targetWord))
wordCount++;
System.out.println(wordCount);
ตัว Vortex Indicator ได้ถูกนำเสนอลงในนิตยสาร for
วนซ้ำ เราเพียงแค่วนซ้ำผ่านอาร์เรย์ ตรวจสอบว่าองค์ประกอบที่แต่ละดัชนีมีค่าเท่ากับ targetWord
. ถ้าใช่ เราจะเพิ่มค่า wordCount
ซึ่งเมื่อสิ้นสุดการดำเนินการ พิมพ์ว่า:
2
นับคำที่เกิดขึ้นในสตริงด้วย คอลเลกชันความถี่ ()
พื้นที่ Collections.frequency()
วิธีการให้การใช้งานในระดับที่สูงกว่าและสะอาดกว่ามากซึ่งสรุปง่าย ๆ for
วนซ้ำและตรวจสอบตัวตนทั้งสอง (ไม่ว่าจะเป็นวัตถุ is วัตถุอื่น) และความเท่าเทียมกัน (ไม่ว่าวัตถุจะเท่ากับวัตถุอื่นหรือไม่ ขึ้นอยู่กับคุณสมบัติเชิงคุณภาพของวัตถุนั้น)
พื้นที่ frequency()
method ยอมรับรายการที่จะค้นหาผ่านและวัตถุเป้าหมายและใช้ได้กับวัตถุอื่น ๆ ทั้งหมดเช่นกันโดยที่พฤติกรรมขึ้นอยู่กับวิธีที่วัตถุนั้นนำไปใช้ equals()
. ในกรณีของสตริง equals()
ตรวจสอบสำหรับ เนื้อหาของสตริง:
searchText = searchText.replaceAll("p{Punct}", "");
int wordCount = Collections.frequency(Arrays.asList(searchText.split(" ")), targetWord);
System.out.println(wordCount);
ที่นี่เราได้แปลงอาร์เรย์ที่ได้รับจาก split()
เป็น Java ArrayList
, โดยใช้ตัวช่วย asList()
วิธีการของ Arrays
ระดับ. การดำเนินการลด frequency()
ส่งกลับจำนวนเต็มที่แสดงถึงความถี่ของ targetWord
ในรายการ และผลลัพธ์ใน:
2
การเกิดขึ้นของคำในสตริงด้วย ตัวจับคู่ (นิพจน์ทั่วไป – RegEx)
สุดท้าย คุณสามารถใช้นิพจน์ทั่วไปเพื่อค้นหารูปแบบ และนับจำนวนรูปแบบที่ตรงกัน นิพจน์ทั่วไปถูกสร้างขึ้นมาเพื่อสิ่งนี้ ดังนั้นจึงมีความเหมาะสมกับงานอย่างเป็นธรรมชาติ ในชวา Pattern
คลาสใช้เพื่อแทนและคอมไพล์ Regular Expressions และ Matcher
คลาสใช้เพื่อค้นหาและจับคู่รูปแบบ
เมื่อใช้ RegEx เราสามารถโค้ดค่าคงที่ของเครื่องหมายวรรคตอนลงในนิพจน์ได้ ดังนั้นจึงไม่จำเป็นต้องจัดรูปแบบสตริงจากภายนอกหรือลบเครื่องหมายวรรคตอน ซึ่งเหมาะสำหรับข้อความขนาดใหญ่ที่การจัดเก็บเวอร์ชันที่แก้ไขอื่นไว้ในหน่วยความจำอาจมีราคาแพง:
Pattern pattern = Pattern.compile("b%s(?!w)".format(targetWord));
Pattern pattern = Pattern.compile("bwants(?!w)");
Matcher matcher = pattern.matcher(searchText);
int wordCount = 0;
while (matcher.find())
wordCount++;
System.out.println(wordCount);
สิ่งนี้ยังส่งผลให้:
2
เกณฑ์มาตรฐานประสิทธิภาพ
แล้วอันไหนมีประสิทธิภาพมากที่สุด? ลองใช้เกณฑ์มาตรฐานเล็ก ๆ กัน:
int runs = 100000;
long start1 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
int result = countOccurencesWithSplit(searchText, targetWord);
}
long end1 = System.currentTimeMillis();
System.out.println(String.format("Array split approach took: %s miliseconds", end1-start1));
long start2 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
int result = countOccurencesWithCollections(searchText, targetWord);
}
long end2 = System.currentTimeMillis();
System.out.println(String.format("Collections.frequency() approach took: %s miliseconds", end2-start2));
long start3 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
int result = countOccurencesWithRegex(searchText, targetWord);
}
long end3 = System.currentTimeMillis();
System.out.println(String.format("Regex approach took: %s miliseconds", end3-start3));
แต่ละวิธีจะถูกเรียกใช้ 100000 ครั้ง (ยิ่งจำนวนสูง ความแปรปรวนและผลลัพธ์ที่ลดลงเนื่องจากโอกาส อันเนื่องมาจากกฎของตัวเลขจำนวนมาก) การรันโค้ดนี้ส่งผลให้:
Array split approach took: 152 miliseconds
Collections.frequency() approach took: 140 miliseconds
Regex approach took: 92 miliseconds
อย่างไรก็ตาม จะเกิดอะไรขึ้นหากเราทำให้การค้นหามีราคาแพงขึ้นด้วยการคำนวณโดยทำให้มีขนาดใหญ่ขึ้น มาสร้างประโยคสังเคราะห์กันเถอะ:
List possibleWords = Arrays.asList("hello", "world ");
StringBuffer searchTextBuffer = new StringBuffer();
for (int i = 0; i < 100; i++) {
searchTextBuffer.append(String.join(" ", possibleWords));
}
System.out.println(searchTextBuffer);
สิ่งนี้สร้างสตริงที่มีเนื้อหา:
hello world hello world hello world hello ...
ดูคู่มือเชิงปฏิบัติสำหรับการเรียนรู้ Git ที่มีแนวทางปฏิบัติที่ดีที่สุด มาตรฐานที่ยอมรับในอุตสาหกรรม และเอกสารสรุปรวม หยุดคำสั่ง Googling Git และจริงๆ แล้ว เรียน มัน!
ถ้าเราจะค้นหาคำว่า "สวัสดี" หรือ "โลก" ก็คงจะมีการจับคู่กันมากกว่าเดิมอีกมาก วิธีการของเราในตอนนี้เป็นอย่างไรในเกณฑ์มาตรฐาน?
Array split approach took: 606 miliseconds
Collections.frequency() approach took: 899 miliseconds
Regex approach took: 801 miliseconds
ตอนนี้การแยกอาร์เรย์ออกมาเร็วที่สุด! โดยทั่วไป การวัดประสิทธิภาพขึ้นอยู่กับปัจจัยต่างๆ เช่น พื้นที่ค้นหา คำเป้าหมาย ฯลฯ และกรณีการใช้งานส่วนตัวของคุณอาจแตกต่างจากเกณฑ์มาตรฐาน
คำแนะนำ: ลองใช้วิธีการในข้อความของคุณเอง จดเวลา และเลือกวิธีที่มีประสิทธิภาพและสง่างามที่สุดสำหรับคุณ
สรุป
ในคู่มือฉบับย่อนี้ เราได้ศึกษาวิธีการนับจำนวนคำที่เกิดขึ้นสำหรับคำเป้าหมายในสตริงใน Java เราเริ่มต้นด้วยการแยกสตริงและใช้ตัวนับอย่างง่าย ตามด้วยการใช้ Collections
คลาสตัวช่วย และสุดท้าย ใช้นิพจน์ทั่วไป
ในท้ายที่สุด เราได้เปรียบเทียบวิธีการต่างๆ และสังเกตว่าประสิทธิภาพไม่ได้เป็นแบบเชิงเส้น และขึ้นอยู่กับพื้นที่ในการค้นหา สำหรับข้อความอินพุตที่ยาวขึ้นซึ่งมีการจับคู่จำนวนมาก การแยกอาร์เรย์น่าจะมีประสิทธิภาพมากที่สุด ลองใช้ทั้งสามวิธีด้วยตัวคุณเอง แล้วเลือกวิธีที่มีประสิทธิภาพมากที่สุด