Як отримати перші п символів рядка, не перевіряючи розмір і не виходячи за межі?


163

Як мені встати до першого n символів рядка на Java, не роблячи перевірки розміру спочатку (вбудований рядковий текст) або не ризикуючи IndexOutOfBoundsException?


1
якщо ви не виберете виняток, я не знаю, як ви плануєте обробляти випадок, коли довжина символу більша за довжину рядка.
— Метт Бьом

2
Чому? Яка ваша відраза до перевірки довжини чи вибору винятку?
— paxdiablo

1
НЕ цікаво, чому ви хочете уникати перевірки розміру. Це не C.
— Том Хоутін - тайклін

що я мав на меті висловити - це бажання уникати блоку if / else, а не відрази до фактичної перевірки довжини.
— antony.trupe

потенціал Дублікат: stackoverflow.com/questions/8499698 / ...
— мулька

Відповіді:


347

Ось акуратне рішення:

String upToNCharacters = s.substring(0, Math.min(s.length(), n));

Думка: хоча це рішення є "акуратним", я думаю, що насправді він менш читабельний, ніж рішення, яке використовує if/ elseочевидно. Якщо читач не бачив цього фокусу, йому / їй доведеться думати важче, щоб зрозуміти код. IMO, значення коду є більш очевидним у if/ elseверсії. Більш чисте / читабельне рішення див. У відповіді @ paxdiablo.


1
+1. Ще краще, якщо це буде вкладено у функцію з назвою safe_substring або substring_safe, як відповідь paxdiablo, так що використання легше читати / наміри більш очевидне.
— ToolmakerSteve

Я не згоден з тим, що ви говорите. Якщо це обгорнуто функцією, не має значення, що знаходиться всередині функції , і будь-яка «акуратність», безумовно, переважає недостатня чіткість. Сенс цього рішення полягає в тому, що воно є "акуратним" для випадку, коли ви не хочете створювати функцію обгортки.
— Стівен C

88

Не винаходити колесо ...:

org.apache.commons.lang.StringUtils.substring(String s, int start, int len)

Javadoc каже:

StringUtils.substring(null, *, *)    = null
StringUtils.substring("", * ,  *)    = "";
StringUtils.substring("abc", 0, 2)   = "ab"
StringUtils.substring("abc", 2, 0)   = ""
StringUtils.substring("abc", 2, 4)   = "c"
StringUtils.substring("abc", 4, 6)   = ""
StringUtils.substring("abc", 2, 2)   = ""
StringUtils.substring("abc", -2, -1) = "b"
StringUtils.substring("abc", -4, 2)  = "ab"

Таким чином:

StringUtils.substring("abc", 0, 4) = "abc"

1
Він не відповідає на питання, але незалежно від того, він все ще пропонує рішення. Якщо ОП може зрозуміти, я вважаю, що це краще рішення.
— аула

5
Також може бути корисним зазначити, що StringUtils.substring(yourString, 0, n)це не те саме, що yourString.substring(0, n). Перший є з StringUtils, а другий використовує String.substring(що дає виняток, якщо кінцевий індекс перевищує довжину рядка).
— ToolmakerSteve

Так само, як FYI, якщо ви шукаєте джерело для цього методу, його обробку випадку, коли кінець більший за довжину, змінивши кінець на довжину:if (end > str.length()) { end = str.length();}
— bholl

1
Останній параметр StringUtils.substring(String s, int start, int len)не покладений, це кінцевий індекс.
— gorootde

StringUtils.substring ("abc", 0, 4) = "abc", працював для мене. Дякую !
— Акаш5288

42

Apache Commons Lang має StringUtils.leftметод для цього.

String upToNCharacters = StringUtils.left(s, n);

Чи не повинно це бути найкращим рішенням? Чому це не багато голосуючих?
— Буде Вілл

3
Може тому, що інші люди не мають такої ж думки, як ви? :-)
— Стівен C

ця відповідь надійшла набагато пізніше, ніж початкова дата запитання.
— мулька

@DoWill: Тому що додавати (іншу) сторонню бібліотеку до виконуваного середовища не завжди варто.
— LarsH

12

Існує клас питань щодо SO, які іноді мають менш ніж ідеальний сенс, це небезпечно близько :-)

Можливо, ви могли б пояснити свою неприязнь використанням одного з двох методів, які ви виключили.

Якщо це не тому, що ви не хочете перецьовувати свій код ifзаявами чи кодом вилучення винятків, одним із варіантів є використання допоміжної функції, яка піклуватиметься про вас, наприклад:

static String substring_safe (String s, int start, int len) { ... }

які заздалегідь перевірять довжини та діятимуть відповідно (або повертайте менший рядок, або колодку з пробілами).

Тоді вам зовсім не доведеться турбуватися про це у своєму коді, просто зателефонуйте:

String s2 = substring_safe (s, 10, 7);

замість:

String s2 = s.substring (10,7);

Це буде працювати в тому випадку, якщо ви, мабуть, переживаєте (на основі ваших коментарів до інших відповідей), не порушуючи потік коду, коли робите велику кількість строкових будівельних речей.


1
Ви повинні прочитати коментар уважніше, @antony, особливо смайлик, і не бути таким дорогоцінним щодо тих, хто намагається допомогти. Я просто заявив, що ви не давали жодних обґрунтувань, чому вам доведеться уникати двох методів. І це справжня відповідь, використовуючи функцію помічника, саме тому це не в коментарі.
— paxdiablo

1
+1: Це набагато кращий підхід, ніж прийнятий, враховуючи бажання ОП не захаращувати код. (Або см рішення Nickkk по включаючи бібліотеку , яка вже має функцію , яка поводиться за бажанням.)
— ToolmakerSteve

12
String upToNCharacters = String.format("%."+ n +"s", str);

Жахливо, якщо nце змінна (тому ви повинні побудувати рядок формату), але досить чітка, якщо константа:

String upToNCharacters = String.format("%.10s", str);

док


Цікава альтернатива, хоча я не можу уявити, що коли-небудь її використовуватиму, враховуючи більш традиційні підходи, що були надані чотири роки тому.
— ToolmakerSteve

Найкраща відповідь, тому що рядок введення читається лише один раз, тому немає необхідності зберігати її в змінній, що дає змогу акуратно вбудовувати її.
— Профітролі

3

Використовуйте метод підрядки наступним чином:

int n = 8;
String s = "Hello, World!";
System.out.println(s.substring(0,n);

Якщо n більше довжини рядка, це призведе до винятку, як вказував один коментатор. одне просте рішення - зафіксувати все це в умові if(s.length()<n)у вашому elseпункті, ви можете вибрати, чи хочете ви просто надрукувати / повернути цілу струну або обробити її іншим способом.


1
це ризикує отримати IndexOutOfBoundsException
— antony.trupe

До речі, якщо ви плануєте програмування на Java, вам слід спробувати запам'ятати більшість методів API для String ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html ).
— Метт Боем

Я вже виключив підрядок, принаймні сам по собі, як не відповідь.
— antony.trupe

Ви повинні або перевірити розмір, або зловити виняток. Чи можу я запитати, чому виконання будь-якого з них не допоможе у вашій ситуації?
— Метт Боем

3
Як це відповідь на запитання? Питання полягало в тому, щоб НЕ потрібно спочатку робити перевірку розміру, а також викликати виняток, який потрібно виловлювати.
— ToolmakerSteve

3

Якщо вам пощастило розвиватися разом з Котліном,
ви можете використовувати takeдля досягнення своєї мети.

val someString = "hello"

someString.take(10) // result is "hello"
someString.take(4) // result is "hell" )))

0

ApacheCommons мене здивував, StringUtils.abbreviate(String str, int maxWidth)додає "..." немає можливості змінювати постфікс. WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)дивиться на наступне порожнє місце.

Я просто залишаю це:

public static String abbreviate(String s, int maxLength, String appendToEnd) {
    String result = s;
    appendToEnd = appendToEnd == null ? "" : appendToEnd;
    if (maxLength >= appendToEnd.length()) {
        if (s.length()>maxLength) {
            result = s.substring(0, Math.min(s.length(), maxLength - appendToEnd.length())) + appendToEnd;
        }
    } else {
        throw new StringIndexOutOfBoundsException("maxLength can not be smaller than appendToEnd parameter length.");
    }
    return result;
}

1
@ VolkanGüven Це через це пропозицію "ApacheCommons мене здивувало". Я вчинив гріх, критикуючи священну бібліотеку ApacheCommons. Або що завгодно ...
— Юсель

0

Котлін: (Якщо комусь потрібно)

var mText = text.substring(0, text.length.coerceAtMost(20))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.