Як я можу прокладати рядок на Java?


431

Чи є якийсь простий спосіб набити струни на Java?

Здається, щось, що повинно бути в API, подібному до StringUtil, але я не можу знайти нічого, що це робить.


Що стосується функції apache проти форматів струн, то мало сумнівів, що функція apache є більш зрозумілою та легкою для читання. Встановлення форматера у назви функцій не є ідеальним.
Terra Caines

Відповіді:


189

Apache StringUtilsмає кілька методів: leftPad, rightPad, centerі repeat.

Але зауважте, що - як уже згадували та демонстрували інші у цій відповіді - String.format()і Formatterзаняття в JDK - кращі варіанти. Використовуйте їх над загальним кодом.


91
java.util.Formatter (і String.format ()) робить це. Завжди віддайте перевагу JDK перед зовнішньою бібліотекою, якщо версія JDK виконує цю роботу (що вона робить).
кліт

6
З кількох причин я б зараз віддав перевагу Гуаві перед Apache Commons; ця відповідь показує, як це зробити в Гуаві .
Джонік

1
@Jonik Ви хотіли б перелічити деякі свої причини? API виглядають майже однаково.
glen3b

3
@ glen3b: Для окремої утиліти, як, наприклад, ці помічники з накладки на струну, вона дійсно не має значення, яку лібу використовувати. Зважаючи на це, Guava загалом є більш сучасним, більш чистим та більш добре підтвердженим документом, ніж його колеги в різних проектах Apache Commons (Commons Lang, Commons Collections, Commons IO тощо). Його також побудували справді розумні хлопці (Кевін Бурліон та ін.), Багато з яких активні в SO . Сам я в кінцевому підсумку замінив різні лінзи Apache Commons просто Гуавою років тому, і не пошкодував.
Джонік


634

Оскільки Java 1.5, String.format()можна використовувати ліву / праву панель заданого рядка.

public static String padRight(String s, int n) {
     return String.format("%-" + n + "s", s);  
}

public static String padLeft(String s, int n) {
    return String.format("%" + n + "s", s);  
}

...

public static void main(String args[]) throws Exception {
 System.out.println(padRight("Howto", 20) + "*");
 System.out.println(padLeft("Howto", 20) + "*");
}

А вихід:

Howto               *
               Howto*

39
Що робити, якщо вам потрібно lpad з іншими символами (а не пробілами)? Чи все-таки можливо за допомогою String.format? Я не в змозі змусити його працювати ...
Гвідо,

6
AFAIK String.format () не може цього зробити, але це не надто складно кодувати , див. Rgagnon.com/javadetails/java-0448.html (2-й приклад)
RealHowTo

61
@ Nullw0rm, якщо ви маєте на увазі rgagnon.com, майте на увазі, що RealHowTo є автором rgagnon.com, тож він би зараховував себе ...
Колін Пікард

3
принаймні, на моєму JVM "#" не працює, "-" нормально. (Просто видаліть #). Це може відповідати документації щодо форматера, я не знаю; в ньому написано "'#' '\ u0023' Потрібен вихід, використовуючи альтернативну форму. Визначення форми визначається перетворенням."
gatoatigrado

6
Дякую за приголомшливу відповідь. Я маю сумніви, хоча для чого це 1$? @leo зробив дуже схожу відповідь, яка не використовується, 1$і, мабуть, має той же ефект. Це має значення?
Fabrício Matté

257

Прокладка до 10 символів:

String.format("%10s", "foo").replace(' ', '*');
String.format("%-10s", "bar").replace(' ', '*');
String.format("%10s", "longer than 10 chars").replace(' ', '*');

вихід:

  *******foo
  bar*******
  longer*than*10*chars

Відобразити "*" для символів пароля:

String password = "secret123";
String padded = String.format("%"+password.length()+"s", "").replace(' ', '*');

Вихід має таку ж довжину, що і рядок пароля:

  secret123
  *********

50
Тільки до тих пір, поки ми всі пам’ятаємо, щоб не проходити в рядку з пробілами ...: D
leviathanbadger

4
Я з @ aboveyou00 - це жахливе рішення для рядків з пробілами, включаючи приклад, наданий leo. Рішення для набивання рядка ліворуч або праворуч не повинно змінювати вхідний рядок, як він відображається у висновку, якщо тільки оригінальна накладка рядка введення не призводить до того, що вона перевищує вказану довжину оббивки.
Брайан Варшо

3
Визначте космічне питання. .replace(' ', '*')швидше призначався, щоб показати ефект накладки. Вираз щодо приховування пароля у цьому випадку не має цієї проблеми ... Для кращої відповіді щодо налаштування лівої та правої рядок накладки за допомогою натопленої функції Java дивіться іншу мою відповідь.
лео

Якщо рядок містить лише окремі пробіли, і ви хочете прокладати різні символи, ви можете використовувати заміни регулярного виразу з оглядом позаду / вперед: String.format("%30s", "pad left").replaceAll("(?<=( |^)) ", "*")абоString.format("%-30s", "pad right").replaceAll(" (?=( |$))", "*")
Ярослав Павлак,


33

Щось просте:

Значення повинно бути рядком. перетворити його в рядок, якщо це не так. Як "" + 123абоInteger.toString(123)

// let's assume value holds the String we want to pad
String value = "123";

Підрядка починається від показника значень довжини значень до кінця довжини прокладеного:

String padded="00000000".substring(value.length()) + value;

// now padded is "00000123"

Більш точно

килимок праворуч:

String padded = value + ("ABCDEFGH".substring(value.length())); 

// now padded is "123DEFGH"

килимок зліва:

String padString = "ABCDEFGH";
String padded = (padString.substring(0, padString.length() - value.length())) + value;

// now padded is "ABCDE123"

24

Погляньте org.apache.commons.lang.StringUtils#rightPad(String str, int size, char padChar).

Але алгоритм дуже простий (вкладка прямо до знаків розміру):

public String pad(String str, int size, char padChar)
{
  StringBuffer padded = new StringBuffer(str);
  while (padded.length() < size)
  {
    padded.append(padChar);
  }
  return padded.toString();
}

11
Зауважте, що на Java 1.5 варто використовувати StringBuilder замість StringBuffer.
Джон Скіт

21

Окрім Apache Commons, також дивіться, String.formatякі повинні мати можливість подбати про прості накладки (наприклад, з пробілами).


17
public static String LPad(String str, Integer length, char car) {
  return (str + String.format("%" + length + "s", "").replace(" ", String.valueOf(car))).substring(0, length);
}

public static String RPad(String str, Integer length, char car) {
  return (String.format("%" + length + "s", "").replace(" ", String.valueOf(car)) + str).substring(str.length(), length + str.length());
}

LPad("Hi", 10, 'R') //gives "RRRRRRRRHi"
RPad("Hi", 10, 'R') //gives "HiRRRRRRRR"
RPad("Hi", 10, ' ') //gives "Hi        "
RPad("Hi", 1, ' ')  //gives "H"
//etc...

4
Зверніть увагу: ви перевернули імена функцій; якщо ви запустите його, ви побачите.
синюватий

плюс якщо оригінальна стрічка містить пробіли, то це не працює
Стівен Шов,

@StevenShaw Якщо я не помиляюся, заміна не націлена на оригінал str, тому це правильно.
мафу

3
За умовами, ви не повинні використовувати велику літеру для імен функцій.
основний-ідеальний домен

Чи є відсутній зумовлюють повернення рядка , як це , коли (length - str.length())це 0? Форматор викидає a, FormatFlagsConversionMismatchExceptionколи %0sце рядок формату.
Девін Уолтерс

7

Це знадобило мені трохи часу, щоб розібратися. Справжній ключ полягає в тому, щоб прочитати цю документацію Форматтера.

// Get your data from wherever.
final byte[] data = getData();
// Get the digest engine.
final MessageDigest md5= MessageDigest.getInstance("MD5");
// Send your data through it.
md5.update(data);
// Parse the data as a positive BigInteger.
final BigInteger digest = new BigInteger(1,md5.digest());
// Pad the digest with blanks, 32 wide.
String hex = String.format(
    // See: http://download.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html
    // Format: %[argument_index$][flags][width]conversion
    // Conversion: 'x', 'X'  integral    The result is formatted as a hexadecimal integer
    "%1$32x",
    digest
);
// Replace the blank padding with 0s.
hex = hex.replace(" ","0");
System.out.println(hex);

Чому зробити кінець таким складним? Ви могли щойно зробити String hex = String.format ("% 032x", дайджест); і мали точно такі самі результати, лише без зайвої заміни () та використання $ для доступу до певних змінних (зрештою, є лише одна)
ArtOfWarfare

@ArtOfWarfare справедлива точка. Хтось спочатку запитував прошивку шестигранних значень в іншому запитанні, я побачив, що у мене є посилання на документацію на форматер. Це складно для повноти.
Nthalk

6

Я знаю, що ця тема є якось давньою, і оригінальне питання було для простого рішення, але якщо це повинно бути дуже швидким, ви повинні використовувати масив char.

public static String pad(String str, int size, char padChar)
{
    if (str.length() < size)
    {
        char[] temp = new char[size];
        int i = 0;

        while (i < str.length())
        {
            temp[i] = str.charAt(i);
            i++;
        }

        while (i < size)
        {
            temp[i] = padChar;
            i++;
        }

        str = new String(temp);
    }

    return str;
}

рішення форматера не є оптимальним. просто побудова рядка формату створює 2 нові рядки.

Рішення apache можна покращити, ініціалізуючи sb з цільовим розміром, замінивши нижче

StringBuffer padded = new StringBuffer(str); 

з

StringBuffer padded = new StringBuffer(pad); 
padded.append(value);

запобігає зростанню внутрішнього буфера sb.


Якщо StringBufferне можна отримати доступ до декількох потоків одночасно (що в цьому випадку істинно), вам слід скористатися StringBuilder(у JDK1.5 +), щоб уникнути накладних витрат синхронізації.
glen3b

5

Ось ще один спосіб накладки праворуч:

// put the number of spaces, or any character you like, in your paddedString

String paddedString = "--------------------";

String myStringToBePadded = "I like donuts";

myStringToBePadded = myStringToBePadded + paddedString.substring(myStringToBePadded.length());

//result:
myStringToBePadded = "I like donuts-------";

5

Оскільки Java 11, String.repeat (int) може бути використаний для прокладки ліворуч / праворуч заданого рядка.

System.out.println("*".repeat(5)+"apple");
System.out.println("apple"+"*".repeat(5));

Вихід:

*****apple
apple*****

1
Найкраща відповідь на java 11!
Nagy Attila

4

Ви можете зменшити накладні витрати за виклик, зберігаючи дані прокладки, а не переробляти їх щоразу:

public class RightPadder {

    private int length;
    private String padding;

    public RightPadder(int length, String pad) {
        this.length = length;
        StringBuilder sb = new StringBuilder(pad);
        while (sb.length() < length) {
            sb.append(sb);
        }
        padding = sb.toString();
   }

    public String pad(String s) {
        return (s.length() < length ? s + padding : s).substring(0, length);
    }

}

Як альтернатива, ви можете зробити довжину результату параметром pad(...)методу. У цьому випадку виконайте налаштування прихованої прокладки в цьому методі, а не в конструкторі.

(Підказка: Щоб отримати додатковий кредит, зробіть це безпечним для ниток! ;-)


1
Це безпечно для потоків, за винятком небезпечної публікації (зробіть ваші поля остаточними). Я думаю, що продуктивність може бути покращена, виконавши підрядку перед позначкою +, яку слід замінити на конмат (як не дивно).
Том Хотін - тайклін

3

Знайшов це на Dzone

Прокладка з нулями:

String.format("|%020d|", 93); // prints: |00000000000000000093|

Це має бути відповідь, проста та лаконічна, не потрібно встановлювати зовнішні бібліотеки.
Вонг Цзя Хау

2

ви можете використовувати вбудований метод StringBuilder append () та insert () для прокладки змінної довжини рядків:

AbstractStringBuilder append(CharSequence s, int start, int end) ;

Наприклад:

private static final String  MAX_STRING = "                    "; //20 spaces

    Set<StringBuilder> set= new HashSet<StringBuilder>();
    set.add(new StringBuilder("12345678"));
    set.add(new StringBuilder("123456789"));
    set.add(new StringBuilder("1234567811"));
    set.add(new StringBuilder("12345678123"));
    set.add(new StringBuilder("1234567812234"));
    set.add(new StringBuilder("1234567812222"));
    set.add(new StringBuilder("12345678122334"));

    for(StringBuilder padMe: set)
        padMe.append(MAX_STRING, padMe.length(), MAX_STRING.length());

2

Це працює:

"".format("%1$-" + 9 + "s", "XXX").replaceAll(" ", "0")

Він заповнить ваш String XXX до 9 символів пробілом. Після цього всі білі простори будуть замінені 0. Ви можете змінити пробіл та 0 на все, що завгодно ...


Ви повинні викликати staticметод, String.format(…)а не зловживати порожнім рядком. Збереження чотирьох символів у вихідному коді точно не варто втрачати читабельність.
Холгер

2
public static String padLeft(String in, int size, char padChar) {                
    if (in.length() <= size) {
        char[] temp = new char[size];
        /* Llenado Array con el padChar*/
        for(int i =0;i<size;i++){
            temp[i]= padChar;
        }
        int posIniTemp = size-in.length();
        for(int i=0;i<in.length();i++){
            temp[posIniTemp]=in.charAt(i);
            posIniTemp++;
        }            
        return new String(temp);
    }
    return "";
}

2

Дозвольте мені залишити відповідь на деякі випадки, що вам потрібно надати ліву / праву накладку (або префікс / суфікс-рядок або пробіли) перед тим, як приєднатись до іншої рядки, і ви не хочете перевіряти довжину чи будь-яку умову.

Як і до обраної відповіді, я вважаю за краще StringUtilsApache Commons, але використовуючи такий спосіб:

StringUtils.defaultString(StringUtils.leftPad(myString, 1))

Поясніть:

  • myString: рядок, який я вводите, може бути нульовим
  • StringUtils.leftPad(myString, 1): якщо рядок є null, це твердження також поверне null
  • потім використовуйте defaultStringдля надання порожнього рядка, щоб запобігти об'єднанню нуля

2

Відповіді @ck та @Marlon Tarak - єдині, які використовують a char[], що для програм, які мають кілька викликів методів прокладки в секунду, є найкращим підходом. Однак вони не користуються будь-якими оптимізаціями маніпулювання масивом і трохи перезаписані на мій смак; це можна зробити зовсім без циклів .

public static String pad(String source, char fill, int length, boolean right){
    if(source.length() > length) return source;
    char[] out = new char[length];
    if(right){
        System.arraycopy(source.toCharArray(), 0, out, 0, source.length());
        Arrays.fill(out, source.length(), length, fill);
    }else{
        int sourceOffset = length - source.length();
        System.arraycopy(source.toCharArray(), 0, out, sourceOffset, source.length());
        Arrays.fill(out, 0, sourceOffset, fill);
    }
    return new String(out);
}

Простий метод тестування:

public static void main(String... args){
    System.out.println("012345678901234567890123456789");
    System.out.println(pad("cats", ' ', 30, true));
    System.out.println(pad("cats", ' ', 30, false));
    System.out.println(pad("cats", ' ', 20, false));
    System.out.println(pad("cats", '$', 30, true));
    System.out.println(pad("too long for your own good, buddy", '#', 30, true));
}

Виходи:

012345678901234567890123456789
cats                          
                          cats
                cats
cats$$$$$$$$$$$$$$$$$$$$$$$$$$
too long for your own good, buddy 

1
Ви можете використовувати, getCharsщоб Stringкопіювати його вміст безпосередньо в outмасив, а не дзвонити source.toCharArray(), після чого System.arraycopy. Я б навіть розглянути можливість спрощення реалізації char[] out = new char[length]; Arrays.fill(out, 0, length, fill); source.getChars(0, source.length(), out, right? 0: length - source.length()); return new String(out);; в той час, як це виглядає, як fillбуло б зробити більше роботи, воно фактично дозволяє JVM усунути заповнення за замовчуванням.
Холгер

1

java.util.Formatterбуде робити лівий і правий накладки. Немає необхідності у чужих сторонніх залежностях (чи хочете ви додати їх до чогось такого тривіального).

[Я покинув деталі та зробив цю публікацію "вікі спільноти", оскільки це не те, у чому я маю потребу.]


4
Я не погоджуюсь. У будь-якому масштабному проекті Java, як правило, робиться стільки маніпуляцій з String, що для більшої читабельності та уникнення помилок варто використовувати Apache Commons Lang. Ви всі знаєте такий код, як someString.subString (someString.indexOf (startCharacter), someString.lastIndexOf (endCharacter)), якого легко уникнути за допомогою StringUtils.
Bananeweizen

1

Усі струнні операції зазвичай мають бути дуже ефективними - особливо якщо ви працюєте з великими наборами даних. Я хотів чогось швидкого та гнучкого, подібного до того, що ви отримаєте в команді plsql pad. Крім того, я не хочу включати величезний ліфт лише для однієї дрібниці. З урахуванням цих міркувань жоден із цих рішень не був задовільним. Це рішення, яке я придумав, що мав найкращі результати відмітки, якщо хтось може покращити його, будь ласка, додайте свій коментар.

public static char[] lpad(char[] pStringChar, int pTotalLength, char pPad) {
    if (pStringChar.length < pTotalLength) {
        char[] retChar = new char[pTotalLength];
        int padIdx = pTotalLength - pStringChar.length;
        Arrays.fill(retChar, 0, padIdx, pPad);
        System.arraycopy(pStringChar, 0, retChar, padIdx, pStringChar.length);
        return retChar;
    } else {
        return pStringChar;
    }
}
  • Зверніть увагу, він викликається за допомогою String.toCharArray (), і результат може бути перетворений в String з новим результатом String ((char [])). Причиною цього є те, що якщо ви застосовуєте кілька операцій, ви можете виконувати їх усе на char [], а не продовжувати конвертувати формати - поза кадром, String зберігається як char []. Якби ці операції були включені до самого класу String, вони були б удвічі ефективнішими - швидкістю та пам'яттю.

Це справді виглядає як найефективніший спосіб
Девід Лілджегрен

1

Використовуйте цю функцію.

private String leftPadding(String word, int length, char ch) {
   return (length > word.length()) ? leftPadding(ch + word, length, ch) : word;
}

як користуватись?

leftPadding(month, 2, '0');

вихід: 01 02 03 04 .. 11 12


1

Дуже багато людей мають дуже цікаві прийоми, але я люблю робити це просто, тому я йду з цим:

public static String padRight(String s, int n, char padding){
    StringBuilder builder = new StringBuilder(s.length() + n);
    builder.append(s);
    for(int i = 0; i < n; i++){
        builder.append(padding);
    }
    return builder.toString();
}

public static String padLeft(String s, int n,  char padding) {
    StringBuilder builder = new StringBuilder(s.length() + n);
    for(int i = 0; i < n; i++){
        builder.append(Character.toString(padding));
    }
    return builder.append(s).toString();
}

public static String pad(String s, int n, char padding){
    StringBuilder pad = new StringBuilder(s.length() + n * 2);
    StringBuilder value = new StringBuilder(n);
    for(int i = 0; i < n; i++){
        pad.append(padding);
    }
    return value.append(pad).append(s).append(pad).toString();
}

2
Це дуже неефективно, вам слід використовувати StringBuilder
wkarl

Оскільки ви вже знаєте довжину, ви повинні сказати StringBuilder виділити стільки місця, коли інстанціюватимете.
Аріель

@Ariel цікаво, що ти це згадуєш, тому що я просто говорив з кимось іншим про це сьогодні, хаха.
Aelphaeis

0

Простим рішенням без будь-якого API буде таке:

public String pad(String num, int len){
    if(len-num.length() <=0) return num;
    StringBuffer sb = new StringBuffer();
    for(i=0; i<(len-num.length()); i++){
        sb.append("0");
    }
    sb.append(num);
    return sb.toString();
}

0

Java oneliners, немає фантазійної бібліотеки.

// 6 characters padding example
String pad = "******";
// testcases for 0, 4, 8 characters
String input = "" | "abcd" | "abcdefgh"

Pad ліворуч, не обмежуйте

result = pad.substring(Math.min(input.length(),pad.length())) + input;
results: "******" | "**abcd" | "abcdefgh"

Pad праворуч, не обмежуйте

result = input + pad.substring(Math.min(input.length(),pad.length()));
results: "******" | "abcd**" | "abcdefgh"

Pad ліворуч, обмежте довжину колодки

result = (pad + input).substring(input.length(), input.length() + pad.length());
results: "******" | "**abcd" | "cdefgh"

Права колодка, обмежте довжину колодки

result = (input + pad).substring(0, pad.length());
results: "******" | "abcd**" | "abcdef"

0

Як щодо використання рекурсії? Наведене нижче рішення сумісне з усіма версіями JDK і не потрібні зовнішні бібліотеки :)

private static String addPadding(final String str, final int desiredLength, final String padBy) {
        String result = str;
        if (str.length() >= desiredLength) {
            return result;
        } else {
            result += padBy;
            return addPadding(result, desiredLength, padBy);
        }
    }

ПРИМІТКА . Це рішення додасть прокладку, трохи переробити ви можете встановити префікс значення.


0

Ось паралельна версія для тих, хто має дуже довгі рядки :-)

int width = 100;
String s = "129018";

CharSequence padded = IntStream.range(0,width)
            .parallel()
            .map(i->i-(width-s.length()))
            .map(i->i<0 ? '0' :s.charAt(i))
            .collect(StringBuilder::new, (sb,c)-> sb.append((char)c), (sb1,sb2)->sb1.append(sb2));

0

-1

Простим рішенням буде:

package nl;
public class Padder {
    public static void main(String[] args) {
        String s = "123" ;
        System.out.println("#"+("     " + s).substring(s.length())+"#");
    }
}

-1

Як це

Рядок "привіт", і необхідна накладка дорівнює 15, а "0" - ліва колодка

String ax="Hello";
while(ax.length() < 15) ax="0"+ax;

10
ця породжує до 15 нових рядків.
claj

@claj Так, але це .
ruffin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.