Программисттин ишинде көбүнчө кээ бир тапшырмалар же алардын компоненттери кайталанышы мүмкүн. Ошондуктан, мен бүгүн ар бир Java иштеп чыгуучунун күнүмдүк ишинде көп жолуккан темага токтолгум келет. Белгилүү бир ыкмадан белгилүү бир сапты алдыңыз деп коёлу. Жана бул жөнүндө баары жакшы көрүнөт, бирок сага туура келбеген бир аз нерсе бар. Мисалы, сепаратор ылайыктуу эмес, жана башка бирөө керек (же такыр жок). Мындай кырдаалда эмне кылса болот?
replace
Албетте, класстын ыкмаларын колдонуңуз String
.
Java сап алмаштыруу
Түр an objectининString
алмаштыруу ыкмасынын төрт варианты бар replace
:
replace(char, char);
replace(CharSequence, CharSequence);
replaceFirst(String, String);
replaceAll(String, String).
replace(char, char)
String replace(char oldChar, char newChar)
- биринчи аргументтин мүнөзүнүн бардык көрүнүштөрүн oldChar
экинчи менен алмаштырат - newChar
. Бул мисалда үтүрдү чекиттүү үтүр менен алмаштырабыз:
String value = "In JavaRush, Diego the best, Diego is Java God".replace(',', ';');
System.out.println(value);
Консолдук чыгаруу:
In JavaRush; Diego the best; Diego is Java God
2.replace(CharSequence, CharSequence)
Белгиленген символдордун ырааттуулугуна дал келген саптын ар бир ички саптарын алмаштыруучу символдордун ырааттуулугу менен алмаштырат.
String value = "In JavaRush, Diego the best, Diego is Java God".replace("Java", "Rush");
System.out.println(value);
Жыйынтык:
In RushRush, Diego the best, Diego is Rush God
3.replaceFirst(String, String)
String replaceFirst(String regex, String replacement)
- Көрсөтүлгөн регулярдуу туюнтмага дал келген биринчи ички сапты алмаштыруучу сап менен алмаштырат. Жараксыз кадимки туюнтманы колдонгондо, сиз PatternSyntaxException кармай аласыз (бул жакшы нерсе эмес). Бул мисалда, келгиле, чемпион роботтун атын алмаштыралы:
String value = "In JavaRush, Diego the best, Diego is Java God".replaceFirst("Diego", "Amigo");
System.out.println(value);
Консолдук чыгаруу:
In JavaRush, Amigo the best, Diego is Java God
Көрүнүп тургандай, "Диегонун" биринчи жазуусу гана өзгөргөн, бирок кийинкилери сыртта калган, башкача айтканда, тийген эмес. 4. replaceAll()
Java-да String replaceAll(String regex, String replacement)
- бул ыкма саптагы подсаптын бардык көрүнүштөрүн regex
менен алмаштырат replacement
. Биринчи аргумент катары кадимки туюнтманы колдонсо болот regex
. Мисал катары, мурунку алмаштырууну аттар менен, бирок жаңы ыкма менен аткарууга аракет кылалы:
String value = "In JavaRush, Diego the best, Diego is Java God".replaceAll("Diego", "Amigo");
System.out.println(value);
Консолдук чыгаруу:
In JavaRush, Amigo the best, Amigo is Java God
Көрүнүп тургандай, бардык символдор толугу менен зарыл болгондор менен алмаштырылган. Мен Амиго ыраазы болот деп ойлойм =)
Регулярдуу туюнтмалар
Туруктуу сөз айкашын колдонуу менен алмаштырууга болот деп жогоруда айтылган. Биринчиден, келгиле, туруктуу сөз айкашынын эмне экенин өзүбүз тактап алалы? Регулярдуу туюнтмалар – метасимволдорду (жапайы белгилерди) колдонууга негизделген тексттеги ички саптарды издөө жана манипуляциялоо үчүн расмий тил. Жөнөкөй сөз менен айтканда, бул издөө эрежесин аныктаган каармандардын жана метабелгилердин үлгүсү. Мисалы:\D
- кандайдыр бир цифралык эмес символду сүрөттөгөн шаблон; \d
— катары да сүрөттөлүшү мүмкүн болгон ар кандай сандык белгини аныктайт [0-9]
; [a-zA-Z]
— адан zге чейинки латын тамгаларын сүрөттөгөн шаблон, регистр сезими жок; Колдонмону replaceAll
класстык ыкмада карап көрүңүз String
:
String value = "In JavaRush, Diego the best, Diego is Java God".replaceAll("\\s[a-zA-Z]{5}\\s", " Amigo ");
System.out.println(value);
Консолдук чыгаруу:
In JavaRush, Amigo the best, Amigo is Java God
\\s[a-zA-Z]{5}\\s
— боштуктар менен курчалган 5 латын тамгаларынан турган сөздү сүрөттөйт. Демек, бул шаблон биз өткөн сап менен алмаштырылат.
Java regex алмаштыруу
Негизинен, Java'да кадимки туюнтмаларды колдонуу үчүнjava.util.regex
, . негизги класстар болуп төмөнкүлөр саналат:
Pattern
- туруктуу сөз айкашынын компиляцияланган versionсын камсыз кылган класс.Matcher
— бул класс үлгүнү чечмелейт жана алган саптагы дал келүүлөрдү аныктайт.
Matcher
Ошентип, биздин мурунку an object кандай болот, бирок жана жардамы менен 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);
Жана биздин корутундубуз бирдей болот:
In JavaRush, Amigo the best, Amigo is Java God
Бул макаладан туруктуу сөз айкаштары жөнүндө көбүрөөк окуй аласыз .
replaceAll үчүн альтернатива
replace
Методдор абдан таасирдүү экени талашсыз , бирок анын an object экенин, башкача айтканда, аны жаратылгандан кийин өзгөртүүгө мүмкүн эмес экенине String
көз жумуп коюуга болбойт . Ошондуктан, ыкмаларды колдонуу менен саптын айрым бөлүктөрүн алмаштырганда , биз an objectти өзгөртпөйбүз , бирок ар бир жолу керектүү мазмун менен жаңысын түзөбүз. Бирок ар бир жолу жаңы an objectти түзүү көп убакытты талап кылат, туурабы? Айрыкча суроо бир-эки an objectиде эмес, жүздөгөн, ал тургай миңдегенде. Албетте, сиз альтернативалар жөнүндө ойлоно баштайсыз. Жана бизде кандай альтернативалар бар? Ммм... Анын менчигине келгенде , сиз дароо альтернативаларды ойлойсуз, бирок эмес , атап айтканда StringBuilder/StringBuffer . Эсибизде тургандай, бул класстар иш жүзүндө айырмаланbyte, бирок алар көп жиптүү чөйрөдө колдонуу үчүн оптималдаштырылган, ошондуктан алар бир жиптүү колдонууда бир аз ылдамыраак иштешет. Ушуга таянып, бүгүн биз колдонобуз Бул класста көптөгөн кызыктуу методдор бар, бирок өзгөчө азыр бизди кызыктырат . — бул ыкма ушул ырааттуулуктун ички сапындагы символдорду көрсөтүлгөн саптагы символдор менен алмаштырат. Кошумча сап көрсөтүлгөн башталгычтан башталат жана индекстин аягындагы символго чейин же андай символ жок болсо, тизмектин аягына чейин уланат. Келгиле, бир мисал карап көрөлү: String
immutable
replace
String
String
immutable
immutable
StringBuffer
StringBuilder
StringBuilder.
replace
StringBuilder replace(int start, int end, String str)
-1
StringBuilder strBuilder = new StringBuilder("Java Rush");
strBuilder.replace(5, 9, "God");
System.out.println(strBuilder);
Жыйынтык:
Java God
Көрүнүп тургандай, биз сапты жазгыбыз келген интервалды көрсөтүп, интервалдагы нерсенин үстүнө субсапты жазабыз. Ошентип, жардамды колдонуп, StringBuilder
биз методдун аналогун кайра түзөбүз replaceall java
. Ал кандай болот:
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();
}
Бул бир караганда коркунучтуу, бирок бир аз түшүнүү менен баары анчалык деле татаал жана логикалуу эмес экенин түшүнүүгө болот.Бизде үч аргумент бар:
str
— биз кээ бир ички саптарды алмаштырууну каалаган сызык;oldStr
— биз алмаштыра турган ички саптардын көрсөтүлүшү;newStr
- аны эмне менен алмаштырабыз.
if
Кирүүчү маалыматтарды текшерүү үчүн бизге биринчи керек жана сап бош str
болсо oldStr
же жаңы субсап newStr
эскиге барабар болсо oldStr
, анда методду аткаруу маанисиз болот. Ошондуктан, биз баштапкы сапты кайтарабыз - str
. Андан кийин, биз текшеребиз newStr
, null
жана эгер ушундай болсо, анда биз аны бизге ыңгайлуу болгон бош сап форматына айландырабыз - ""
. Андан кийин бизге керектүү өзгөрмөлөрдүн декларациясы бар:
- саптын жалпы узундугу
str
; - подсап узундугу
oldStr
; StringBuilder
жалпы саптан an object .
StringBuilder
- indexOf
- бизди кызыктырган подсаптын биринчи жолу кездешүүсүнүн индексин табабыз. Тилекке каршы, мен бул регулярдуу туюнтмалар менен иштебей турганын белгилегим келет indexOf
, ошондуктан биздин акыркы методубуз саптардын пайда болушу менен гана иштейт (( Бул индекс ге барабар болсо -1
, анда азыркы an objectте мындай көрүнүштөрдүн мындан ары кайталануусу жок StringBuilder
, Ошентип, биз кызыгуунун натыйжасы менен методдон чыгабыз: ал биздин , колдонуу StringBuilder
менен конвертациялоодо камтылган.Эгерде биздин индекс циклдин биринчи итерациясында бирдей болсо , анда алмаштырылышы керек болгон ички сап жалпы эмес болгон. сап башында.Ошондуктан, мындай кырдаалда биз жөн гана жалпы сапты кайтарабыз.Андан кийин бизде бар жана жогоруда сүрөттөлгөн ыкма көрүнүштүн табылган индексин колдонуу үчүн алмаштырыла турган ички саптын координаталарын көрсөтүү үчүн колдонулат.Бул цикл иштейт. алмаштырылышы керек болгон ички саптар канча жолу табылса, сап алмаштырылышы керек болгон символдон гана турса, анда бул учурда гана цикл толугу менен иштейт жана натыйжаны сапка айландырабыз . Бул ыкманын тууралыгын текшеришибиз керек, туурабы? Ар кандай кырдаалдарда методдун иштешин текшерген тест жазалы: String
toString
-1
replace
StringBuilder
StringBuilder
@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, "");
}
7 өзүнчө тестке бөлүнүшү мүмкүн, алардын ар бири өзүнүн сыноо иши үчүн жооп берет. Аны ишке киргизип, анын жашыл экенин, башкача айтканда ийгorктүү экенин көрөбүз. Ооба, баары ушундай окшойт. replaceAll
Күтө турсаңыз да, биз жогоруда бул ыкма String
. Мейли, карап көрөлү:
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);
Андан кийин, бул code үч жолу иштетилди жана биз төмөнкү натыйжаларды алдык: Console чыгаруу:
Performance ratio - 5.012148941181627
Performance ratio - 5.320637176017641
Performance ratio - 4.719192686500394
Көрүнүп тургандай, биздин ыкма орто эсеп менен классикалык replaceAll
класска караганда String
5 эсе жемиштүү! Мейли, акыры, ошол эле текшерүүнү жүргүзөлү, бирок, мындайча айтканда, бекер. Башка сөз менен айтканда, эч кандай дал табылган учурда. "tyu"
Издөө сабын дан баштап алмаштыралы "--"
. Үч чуркоо төмөнкү натыйжаларды берди: Консолдун чыгышы:
Performance ratio - 8.789647093542246
Performance ratio - 9.177105482660881
Performance ratio - 8.520964375227406
Орточо алганда, эч кандай дал келбеген учурлар боюнча көрсөткүчтөр 8,8 эсеге өскөн!
GO TO FULL VERSION