JavaRush /Java блогу /Random-KY /Javaдагы сапты алмаштырыңыз

Javaдагы сапты алмаштырыңыз

Группада жарыяланган
Программисттин ишинде көбүнчө кээ бир тапшырмалар же алардын компоненттери кайталанышы мүмкүн. Ошондуктан, мен бүгүн ар бир Java иштеп чыгуучунун күнүмдүк ишинде көп жолуккан темага токтолгум келет. Java'дагы сапты алмаштыруу - 1Белгилүү бир ыкмадан белгилүү бир сапты алдыңыз деп коёлу. Жана бул жөнүндө баары жакшы көрүнөт, бирок сага туура келбеген бир аз нерсе бар. Мисалы, сепаратор ылайыктуу эмес, жана башка бирөө керек (же такыр жок). Мындай кырдаалда эмне кылса болот? replaceАлбетте, класстын ыкмаларын колдонуңуз String.

Java сап алмаштыруу

Түр an objectинин Stringалмаштыруу ыкмасынын төрт варианты бар replace:
  • replace(char, char);
  • replace(CharSequence, CharSequence);
  • replaceFirst(String, String);
  • replaceAll(String, String).
Бул ыкмалардын бардыгынын максаты бир - саптын бир бөлүгүн башка сап менен алмаштыруу. Келгиле, аларды кененирээк карап чыгалы. 1.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, . негизги класстар болуп төмөнкүлөр саналат:
  1. Pattern- туруктуу сөз айкашынын компиляцияланган versionсын камсыз кылган класс.
  2. 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, бирок алар көп жиптүү чөйрөдө колдонуу үчүн оптималдаштырылган, ошондуктан алар бир жиптүү колдонууда бир аз ылдамыраак иштешет. Ушуга таянып, бүгүн биз колдонобуз Бул класста көптөгөн кызыктуу методдор бар, бирок өзгөчө азыр бизди кызыктырат . — бул ыкма ушул ырааттуулуктун ички сапындагы символдорду көрсөтүлгөн саптагы символдор менен алмаштырат. Кошумча сап көрсөтүлгөн башталгычтан башталат жана индекстин аягындагы символго чейин же андай символ жок болсо, тизмектин аягына чейин уланат. Келгиле, бир мисал карап көрөлү: StringimmutablereplaceStringJava-дагы сапты алмаштыруу - 2StringimmutableimmutableStringBufferStringBuilderStringBuilder.replaceStringBuilder 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менен конвертациялоодо камтылган.Эгерде биздин индекс циклдин биринчи итерациясында бирдей болсо , анда алмаштырылышы керек болгон ички сап жалпы эмес болгон. сап башында.Ошондуктан, мындай кырдаалда биз жөн гана жалпы сапты кайтарабыз.Андан кийин бизде бар жана жогоруда сүрөттөлгөн ыкма көрүнүштүн табылган индексин колдонуу үчүн алмаштырыла турган ички саптын координаталарын көрсөтүү үчүн колдонулат.Бул цикл иштейт. алмаштырылышы керек болгон ички саптар канча жолу табылса, сап алмаштырылышы керек болгон символдон гана турса, анда бул учурда гана цикл толугу менен иштейт жана натыйжаны сапка айландырабыз . Бул ыкманын тууралыгын текшеришибиз керек, туурабы? Ар кандай кырдаалдарда методдун иштешин текшерген тест жазалы: StringtoString-1replaceStringBuilderStringBuilder
@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класска караганда String5 эсе жемиштүү! Мейли, акыры, ошол эле текшерүүнү жүргүзөлү, бирок, мындайча айтканда, бекер. Башка сөз менен айтканда, эч кандай дал табылган учурда. "tyu"Издөө сабын дан баштап алмаштыралы "--". Үч чуркоо төмөнкү натыйжаларды берди: Консолдун чыгышы:
Performance ratio  - 8.789647093542246
 
Performance ratio  - 9.177105482660881
 
Performance ratio  - 8.520964375227406
Орточо алганда, эч кандай дал келбеген учурлар боюнча көрсөткүчтөр 8,8 эсеге өскөн! Java-дагы сапты алмаштыруу - 4
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION