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


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.