Як я можу прокладати рядок на 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.