Dalam pekerjaan seorang programmer, seringkali beberapa tugas atau komponennya diulangi. Oleh karena itu, hari ini saya ingin menyentuh topik yang sering ditemui dalam pekerjaan sehari-hari setiap pengembang Java.
Anggaplah Anda menerima string tertentu dari metode tertentu. Dan segala sesuatu tentangnya tampak baik-baik saja, tetapi ada beberapa hal kecil yang tidak cocok untuk Anda. Misalnya, pemisahnya tidak cocok, dan Anda memerlukan pemisah lain (atau tidak sama sekali). Apa yang bisa dilakukan dalam situasi seperti ini? Tentu saja, gunakan metode
replace
kelas
String
.
Penggantian string Java
Tipe objek
String
memiliki empat variasi metode penggantian
replace
:
replace(char, char);
replace(CharSequence, CharSequence);
replaceFirst(String, String);
replaceAll(String, String).
Tujuan dari semua metode ini adalah sama - mengganti bagian dari sebuah string dengan string lain. Mari kita lihat lebih dekat.
1.replace(char, char)
String replace(char oldChar, char newChar)
- menggantikan semua kemunculan karakter argumen pertama
oldChar
dengan argumen kedua -
newChar
. Dalam contoh ini, kami akan mengganti koma dengan titik koma:
String value = "In JavaRush, Diego the best, Diego is Java God".replace(',', ';');
System.out.println(value);
Keluaran konsol:
In JavaRush; Diego the best; Diego is Java God
2.replace(CharSequence, CharSequence)
Mengganti setiap substring dari string yang cocok dengan rangkaian karakter tertentu dengan rangkaian karakter pengganti.
String value = "In JavaRush, Diego the best, Diego is Java God".replace("Java", "Rush");
System.out.println(value);
Kesimpulan:
In RushRush, Diego the best, Diego is Rush God
3.replaceFirst(String, String)
String replaceFirst(String regex, String replacement)
- Mengganti substring pertama yang cocok dengan ekspresi reguler yang ditentukan dengan string pengganti. Saat menggunakan ekspresi reguler yang tidak valid, Anda dapat menangkap
PatternSyntaxException (yang bukan merupakan hal yang baik). Dalam contoh ini, mari kita ganti nama robot juara:
String value = "In JavaRush, Diego the best, Diego is Java God".replaceFirst("Diego", "Amigo");
System.out.println(value);
Keluaran konsol:
In JavaRush, Amigo the best, Diego is Java God
Seperti yang bisa kita lihat, hanya entri pertama “Diego” yang berubah, namun entri berikutnya tetap ditinggalkan—artinya, tidak tersentuh.
4. replaceAll()
di Java String replaceAll(String regex, String replacement)
- metode ini menggantikan semua kemunculan substring dalam string
regex
dengan
replacement
. Ekspresi reguler dapat digunakan sebagai argumen pertama
regex
. Sebagai contoh, mari kita coba melakukan penggantian sebelumnya dengan nama, tetapi dengan metode baru:
String value = "In JavaRush, Diego the best, Diego is Java God".replaceAll("Diego", "Amigo");
System.out.println(value);
Keluaran konsol:
In JavaRush, Amigo the best, Amigo is Java God
Seperti yang bisa kita lihat, semua simbol telah diganti sepenuhnya dengan simbol yang diperlukan. Saya pikir Amigo akan senang =)
Ekspresi Reguler
Telah dikatakan di atas bahwa dimungkinkan untuk mengganti menggunakan ekspresi reguler. Pertama, mari kita perjelas sendiri apa itu ekspresi reguler?
Ekspresi reguler adalah bahasa formal untuk mencari dan memanipulasi substring dalam teks, berdasarkan penggunaan metakarakter (wildcard). Sederhananya, ini adalah pola karakter dan metakarakter yang mendefinisikan aturan pencarian. Misalnya:
\D
- templat yang menjelaskan karakter non-digital apa pun;
\d
— mendefinisikan karakter numerik apa pun, yang juga dapat digambarkan sebagai
[0-9]
;
[a-zA-Z]
— templat yang mendeskripsikan karakter Latin dari a hingga z, tidak peka huruf besar/kecil; Pertimbangkan penerapan dalam metode
replaceAll
kelas
String
:
String value = "In JavaRush, Diego the best, Diego is Java God".replaceAll("\\s[a-zA-Z]{5}\\s", " Amigo ");
System.out.println(value);
Keluaran konsol:
In JavaRush, Amigo the best, Amigo is Java God
\\s[a-zA-Z]{5}\\s
— mendeskripsikan kata yang terdiri dari 5 karakter Latin yang dikelilingi spasi. Oleh karena itu, templat ini diganti dengan string yang kami lewati.
Penggantian regex Java
Pada dasarnya, untuk menggunakan ekspresi reguler di Java, kemampuan
java.util.regex
. Kelas-kelas utamanya adalah:
Pattern
- kelas yang menyediakan versi ekspresi reguler yang dikompilasi.
Matcher
— kelas ini menafsirkan pola dan menentukan kecocokan dalam string yang diterimanya.
Biasanya, kedua kelas ini bekerja bersamaan. Jadi, seperti apa objek kita sebelumnya, tapi dengan bantuan
Matcher
dan
Pattern
:
Pattern pattern = Pattern.compile("\\s[a-zA-Z]{5}\\s");
Matcher matcher = pattern.matcher("In JavaRush, Diego the best, Diego is Java God");
String value = matcher.replaceAll(" Amigo ");
System.out.println(value);
Dan kesimpulan kami akan sama:
In JavaRush, Amigo the best, Amigo is Java God
Anda dapat membaca lebih lanjut tentang ekspresi reguler
di artikel ini .
Alternatif untuk menggantikanSemua
Tidak ada keraguan bahwa metodenya
replace
sangat
String
mengesankan, tetapi kita tidak dapat mengabaikan fakta bahwa
String
itu adalah
immutable
sebuah objek, yaitu, tidak dapat diubah setelah penciptaannya. Oleh karena itu, ketika kita mengganti beberapa bagian string menggunakan metode
replace
, kita tidak mengubah objeknya
String
, tetapi membuat objek baru setiap kali, dengan konten yang diperlukan. Tapi butuh waktu lama untuk membuat objek baru setiap saat, bukan? Apalagi yang ditanyakan bukan beberapa benda, melainkan beberapa ratus, bahkan ribuan. Mau tak mau, Anda mulai memikirkan alternatif lain. Dan alternatif apa yang kita punya?
Hmm... Kalau soal
String
propertinya
immutable
, Anda langsung memikirkan alternatifnya, tapi tidak
immutable
, yaitu
StringBuilder/StringBuffer . Seperti yang kita ingat, kelas-kelas ini sebenarnya tidak berbeda, kecuali bahwa
StringBuffer
mereka dioptimalkan untuk digunakan dalam lingkungan multi-thread, sehingga
StringBuilder
mereka bekerja lebih cepat dalam penggunaan single-thread. Berdasarkan hal ini, hari ini kita akan menggunakan
StringBuilder.
Kelas ini memiliki banyak metode menarik, tetapi secara khusus sekarang kita tertarik pada
replace
.
StringBuilder replace(int start, int end, String str)
— metode ini mengganti karakter dalam substring dari urutan ini dengan karakter dalam string yang ditentukan. Substring dimulai dari awal yang ditentukan dan berlanjut hingga karakter di akhir indeks,
-1
atau hingga akhir urutan jika tidak ada karakter tersebut. Mari kita lihat sebuah contoh:
StringBuilder strBuilder = new StringBuilder("Java Rush");
strBuilder.replace(5, 9, "God");
System.out.println(strBuilder);
Kesimpulan:
Java God
Seperti yang Anda lihat, kami menunjukkan interval di mana kami ingin menulis string, dan menulis substring di atas apa yang ada dalam interval tersebut. Jadi, dengan menggunakan bantuan tersebut,
StringBuilder
kami akan membuat ulang analog dari metode ini
replaceall java
. Bagaimana tampilannya:
public static String customReplaceAll(String str, String oldStr, String newStr) {
if ("".equals(str) || "".equals(oldStr) || oldStr.equals(newStr)) {
return str;
}
if (newStr == null) {
newStr = "";
}
final int strLength = str.length();
final int oldStrLength = oldStr.length();
StringBuilder builder = new StringBuilder(str);
for (int i = 0; i < strLength; i++) {
int index = builder.indexOf(oldStr, i);
if (index == -1) {
if (i == 0) {
return str;
}
return builder.toString();
}
builder = builder.replace(index, index + oldStrLength, newStr);
}
return builder.toString();
}
Sekilas memang menakutkan, tetapi dengan sedikit pemahaman Anda dapat memahami bahwa semuanya tidak begitu rumit dan cukup logis. Kami memiliki tiga argumen:
str
— baris di mana kita ingin mengganti beberapa substring;
oldStr
— representasi substring yang akan kami ganti;
newStr
- dengan apa kami akan menggantinya.
if
Kita memerlukan yang pertama untuk memeriksa data yang masuk, dan jika
str
stringnya
oldStr
kosong, atau substring baru
newStr
sama dengan yang lama
oldStr
, maka menjalankan metode ini tidak akan ada artinya. Oleh karena itu, kami mengembalikan string asli -
str
. Selanjutnya, kami memeriksa
newStr
,
null
dan jika demikian, kami mengubahnya menjadi format string kosong yang lebih nyaman bagi kami -
""
. Kemudian kita mendeklarasikan variabel yang kita perlukan:
- total panjang senar
str
;
- panjang substring
oldStr
;
- objek
StringBuilder
dari string bersama.
Kita memulai perulangan yang seharusnya berjalan beberapa kali sama dengan panjang total string (tetapi, kemungkinan besar, ini tidak akan pernah terjadi). Menggunakan metode kelas
StringBuilder
-
indexOf
- kita mengetahui indeks kemunculan pertama dari substring yang kita minati. Sayangnya, saya ingin mencatat bahwa ini
indexOf
tidak berfungsi dengan ekspresi reguler, jadi metode terakhir kami hanya akan bekerja dengan kemunculan string (( Jika indeks ini sama dengan
-1
, maka tidak ada lagi kemunculan ini di objek saat ini
StringBuilder
, jadi kita keluar dari metode dengan hasil yang menarik: itu terkandung dalam
StringBuilder
, yang kita ubah menjadi
String
, menggunakan
toString
Jika indeks kita sama
-1
pada iterasi pertama dari loop, maka substring yang perlu diganti tidak ada pada umumnya string awalnya. Oleh karena itu, dalam situasi seperti ini, kita hanya mengembalikan string umum. Selanjutnya kita punya dan metode yang dijelaskan di atas digunakan
replace
untuk
StringBuilder
menggunakan indeks kejadian yang ditemukan untuk menunjukkan koordinat substring yang akan diganti. Loop ini akan berjalan sebanyak substring yang perlu diganti ditemukan. Jika string hanya terdiri dari karakter yang perlu diganti, maka hanya dalam kasus ini kita memiliki Perulangan akan berjalan sepenuhnya dan kita akan mendapatkan hasilnya
StringBuilder
diubah menjadi string. Kita perlu memeriksa kebenaran metode ini, bukan? Mari kita menulis tes yang memeriksa pengoperasian metode dalam berbagai situasi:
@Test
public void customReplaceAllTest() {
String str = "qwertyuiop__qwertyuiop__";
String firstCase = Solution.customReplaceAll(str, "q", "a");
String firstResult = "awertyuiop__awertyuiop__";
assertEquals(firstCase, firstResult);
String secondCase = Solution.customReplaceAll(str, "q", "ab");
String secondResult = "abwertyuiop__abwertyuiop__";
assertEquals(secondCase, secondResult);
String thirdCase = Solution.customReplaceAll(str, "rtyu", "*");
String thirdResult = "qwe*iop__qwe*iop__";
assertEquals(thirdCase, thirdResult);
String fourthCase = Solution.customReplaceAll(str, "q", "");
String fourthResult = "wertyuiop__wertyuiop__";
assertEquals(fourthCase, fourthResult);
String fifthCase = Solution.customReplaceAll(str, "uio", "");
String fifthResult = "qwertyp__qwertyp__";
assertEquals(fifthCase, fifthResult);
String sixthCase = Solution.customReplaceAll(str, "", "***");
assertEquals(sixthCase, str);
String seventhCase = Solution.customReplaceAll("", "q", "***");
assertEquals(seventhCase, "");
}
Dapat dibagi menjadi 7 pengujian terpisah, yang masing-masing akan bertanggung jawab atas kasus pengujiannya sendiri. Setelah diluncurkan, kita akan melihatnya hijau, yaitu sukses. Yah, sepertinya itu saja. Meskipun tunggu, kami katakan di atas bahwa metode ini akan jauh lebih cepat
replaceAll
daripada
String
. Baiklah, mari kita lihat:
String str = "qwertyuiop__qwertyuiop__";
long firstStartTime = System.nanoTime();
for (long i = 0; i < 10000000L; i++) {
str.replaceAll("tyu", "#");
}
double firstPerformance = System.nanoTime() - firstStartTime;
long secondStartTime = System.nanoTime();
for (long i = 0; i < 10000000L; i++) {
customReplaceAll(str, "tyu", "#");
}
double secondPerformance = System.nanoTime() - secondStartTime;
System.out.println("Performance ratio - " + firstPerformance / secondPerformance);
Selanjutnya, kode ini dijalankan tiga kali dan kami mendapatkan hasil sebagai berikut: Output konsol:
Performance ratio - 5.012148941181627
Performance ratio - 5.320637176017641
Performance ratio - 4.719192686500394
Seperti yang bisa kita lihat, rata-rata metode kita 5 kali lebih produktif dibandingkan
replaceAll
kelas klasik!
String
Dan akhirnya, mari kita lakukan pemeriksaan yang sama, tetapi, bisa dikatakan, sia-sia. Dengan kata lain, jika tidak ditemukan kecocokan. Mari kita ganti string pencarian dari
"tyu"
menjadi
"--"
. Tiga proses menghasilkan hasil sebagai berikut: Output konsol:
Performance ratio - 8.789647093542246
Performance ratio - 9.177105482660881
Performance ratio - 8.520964375227406
Rata-rata, kinerja untuk kasus di mana tidak ditemukan kecocokan meningkat sebesar 8,8 kali lipat!
Apa lagi yang harus dibaca: |
|
GO TO FULL VERSION