Порівняння рядків

У класі String є кілька методів для порівняння рядків і їх окремих частин Проте, перед тим як переходити до конкретних методів, необхідно зупинитися на деяких аспектах, що стосуються інтернаціональних і локалізованих рядків

Unicode, що не враховуються цими методами Наприклад, при порівнянні двох рядків і

спробі визначити, яка з них більше, відбувається числове порівняння символів відповідно до їх значеннями в кодуванні Unicode, а не їх порядком в локалізованому поданні Для француза символи c і з – це однакові літери, що відрізняються між собою лише маленьким діакритичним значком Впорядковуючи набір рядків, француз проігнорує відмінності між ними і поставить aзa перед acz. Однак з Unicode справа йде інакше – в наборі символів Unicode c (\ u0063) йде перед з (\ u00e7), так що при сортуванні ці рядки виявляться розташованими у зворотному порядку

Перша операція порівняння, equals, повертає true, якщо їй передається посилання на обєкт String з тим же вмістом, що і у поточного обєкта, – тобто якщо рядки мають однакову довжину і складаються в точності з однакових символів Unicode Якщо інший обєкт не відноситься до типу String або ж має інший вміст, то Stringequals повертає false

Щоб порівнювати рядки без урахування регістру, використовуйте метод equals IgnoreCase Під виразом без урахування регістру ми маємо на увазі, що символи Л і л вважаються однаковими, але відрізняються від E і e Символи, для яких поняття регістру не визначено (наприклад, знаки пунктуації) вважаються рівними тільки собі самим У Unicode є багато цікавих аспектів, повязаних з регістром символів, в тому числі і поняття заголовного регістра (title case) Робота з регістром в класі String описується в термінах реєстрових методів класу Character в розділі 135

Для проведення сортування рядків потрібно мати можливість порівнювати їх між собою Метод compareTo повертає значення int, яке менше, дорівнює або більше нуля, якщо рядок, для якої він був викликаний, відповідно менше, дорівнює або більше іншого рядка При порівнянні рядків використовується кодування символів в Unicode

Метод compareTo корисний при створенні внутрішнього канонічного впорядкування рядків Наприклад, при проведенні бінарного пошуку необхідно мати відсортований список елементів, однак при цьому не потрібно, щоб порядок сортування збігався з порядком символів в локалізованому алфавіті Метод бінарного пошуку для класу, в якому є відсортований масив рядків, виглядає наступним чином:

private String[] table

public int position(String key) {

int lo = 0

int hi = tablelength – 1

while (lo &lt&lt= hi) {

int mid = lo + (hi – lo) / 2

int cmp = keycompareTo(table[mid])

if (cmp == 0) / / знайшли

return mid

else if (cmp << 0) / / шукати в нижній половині

hi = mid – 1

else / / шукати в верхній половині

lo = mid + 1

}

return -1 //

}

Так виглядає базовий алгоритм бінарного пошуку Спочатку він перевіряє середню точку досліджуваного діапазону і порівнює значення ключа пошуку з елементом у цій позиції Якщо значення збігаються, то потрібний елемент знайдено, а пошук закінчений Якщо значення ключа менше елемента у перевіреній позиції, то далі пошук буде вестися в нижній половині діапазону в іншому випадку елемент необхідно шукати у верхній половині діапазону В результаті роботи алгоритму або буде знайдений потрібний елемент, або нижня межа діапазону перевищить верхню – це означає, що ключ відсутній у списку

Порівнювати можна не тільки цілі рядки, але і їх окремі частини Для цього застосовується метод regionMatches у двох формах: в одній відбувається точне порівняння символів, як у методі equals, а в іншій – порівняння без урахування регістру, як у методі equalsIgnoreCase:

public boolean regionMatches(int  start, String other, int ostart, int len)

Повертає true, якщо зазначена подстрока даного обєкта String збігається із зазначеною підрядком рядки other Перевірка починається з позиції start в цьому рядку, і з позиції ostart – у рядку other Порівнюються тільки перші len символів

public boolean regionMatches(boolean ignoreCase, int start, String other, int ostart, int len)

Дана версія regionMatches поводиться точно так само, як і попередня, за винятком того, що логічна змінна ignoreCase визначає, чи слід ігнорувати регістр символів при порівнянні

Наведемо приклад:

class RegionMatch {

public static void main(String[] args) { String str = &quotLook, look"

boolean b1, b2, b3

b1 = strregionMatches(6, &quotLook,&quot 0, 4)

b2 = strregionMatches(true, 6, &quotLook,&quot 0, 4)

b3 = strregionMatches(true, 6, &quotLook,&quot 0, 5)

Systemout println(&quotb1 = &quot + b1) Systemout println(&quotb2 = &quot + b2) Systemout println(&quotb3 = &quot + b3)

}

}

Результати роботи будуть виглядати наступним чином:

b1 = false b2 = true b3 = false

Результат першого порівняння дорівнює false, тому що в позиції 6 головною рядка знаходиться символ l, а в позиції 0 другого рядка – символ L. Друге порівняння дає true, оскільки регістр не враховується Нарешті, результат третього порівняння виявляється рівним false, тому що довжина порівнюєш підрядка дорівнює 5, а на протяг цих 5 символів рядка відрізняються навіть без урахування регістру

Проста перевірка на збіг аргументу з початком або кінцем рядка здійснюється за допомогою методів startsWith і endsWith:

public boolean startsWith(String  prefix, int toffset)

Повертає true, якщо рядок починається з підрядка prefix (зі зміщенням toffset) public boolean startsWith(String  prefix)

Скорочення для startsWith (prefix, 0)

public boolean endsWith(String  suffix)

Повертає true, якщо рядок закінчується підрядком suffix

Взагалі кажучи, рядки не можуть порівнюватися з використанням оператора ==, як показано нижче:

if (str == ВPeсa”)

answer(str)

Такий запис не аналізує вміст двох рядків Вона порівнює тільки посилання на один обєкт (str) з посиланням на інший обєкт (неявний строковий обєкт, представлений константою ВPeсa”) Навіть якщо обидва обєкти-рядки мають однаковий вміст, посилання на них можуть різнитися

Проте два будь строкових литерала з однаковим вмістом вказуватимуть на один і той же обєкт класу String Наприклад, в наступному фрагменті оператор ==, ймовірно, спрацює правильно:

String str = &quot?Pena"

// ..

if (str == &quot?Pena&quot)

answer(str)

Через те, що str спочатку був привласнений строковий літерал, порівняння цієї змінної з іншим строковим літералом рівносильно перевірці цих рядків на однаковий зміст І все ж необхідно дотримуватися обережність – цей трюк спрацює лише в тому випадку, якщо ви впевнені в походженні всіх посилань на рядкові літерали Якщо str зміниться і буде вказувати на похідний обєкт

String – наприклад, на результат введення користувачем чого-небудь, – оператор == поверне

значення false, навіть якщо користувач набере рядок ВPeсa.

83 Допоміжні методи

Клас String містить два методи, які виявляються корисними в спеціалізованих додатках Один з них – hashCode, який повертає хеш-код, заснований на вмісті рядка Будь-які два рядки з однаковим вмістом будуть мати однакове значення хеш-коду, хоча і дві різні рядки теж можуть мати однаковий хеш-код Хеш-коди потрібні для роботи з хеш-таблицями, такими, наприклад, як у класі Hashtable з javautil

Другий допоміжний метод, intern, повертає рядок, вміст якої збігається з вмістом вихідної рядка Однак для будь-яких двох рядків з однаковим вмістом intern повертає посилання на один і той же обєкт String, що дозволяє перевіряти рівність рядків допомогою порівняння посилань замість більш повільної перевірки вмісту рядків Розглянемо приклад:

int putIn(String key) {

String uniqe = keyintern()

int i

/ / Перевірити, чи є такий елемент в таблиці

for ( i = 0 i &lt&lt tableSize i++)

if (table[i] == unique)

return i

/ / Якщо ні – додати table [i] = unique tableSize + +

return i

}

Всі рядки, що зберігаються в масиві table, отримані в результаті виклику intern Масив проглядається в пошуках рядки, вміст якої збігається з key Якщо рядок знайдено, то пошук завершується Якщо ж такого рядка немає, в кінець масиву додається рядок, вміст якої збігається з вмістом key При роботі з результатами викликів intern порівняння посилань на обєкти еквівалентно порівнянні вмісту рядків, однак відбувається істотно швидше

Джерело: Арнольд К, Гослінг Д – Мова програмування Java (1997)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*