Java: นับจำนวนคำที่เกิดขึ้นในสตริง

โหนดต้นทาง: 1719850

บทนำ

การนับจำนวนคำที่เกิดขึ้นในสตริงเป็นงานที่ค่อนข้างง่าย แต่มีหลายวิธีในการทำเช่นนั้น คุณต้องคำนึงถึงประสิทธิภาพของวิธีการด้วย เนื่องจากโดยปกติคุณต้องการใช้เครื่องมืออัตโนมัติเมื่อคุณไม่ต้องการใช้แรงงานคน เช่น เมื่อพื้นที่ค้นหามีขนาดใหญ่

ในคู่มือนี้ คุณจะได้เรียนรู้วิธีนับจำนวนคำที่เกิดขึ้นในสตริงใน 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 คลาสตัวช่วย และสุดท้าย ใช้นิพจน์ทั่วไป

ในท้ายที่สุด เราได้เปรียบเทียบวิธีการต่างๆ และสังเกตว่าประสิทธิภาพไม่ได้เป็นแบบเชิงเส้น และขึ้นอยู่กับพื้นที่ในการค้นหา สำหรับข้อความอินพุตที่ยาวขึ้นซึ่งมีการจับคู่จำนวนมาก การแยกอาร์เรย์น่าจะมีประสิทธิภาพมากที่สุด ลองใช้ทั้งสามวิธีด้วยตัวคุณเอง แล้วเลือกวิธีที่มีประสิทธิภาพมากที่สุด

ประทับเวลา:

เพิ่มเติมจาก สแต็ค