Как я могу дополнить строку в Java?

432

Есть ли какой-нибудь простой способ дополнить строки в Java?

Похоже, что-то должно быть в каком-то StringUtil-подобном API, но я не могу найти ничего, что делает это.

pvgoddijn
источник
В вопросе о функции apache против средства форматирования строк нет никаких сомнений в том, что функция apache более понятна и проста для чтения. Обертывание форматера в именах функций не идеально.
Терра Кейнс

Ответы:

189

Apache StringUtilsимеет несколько методов: leftPad, rightPad, centerи repeat.

Но, пожалуйста, обратите внимание, что - как уже упоминалось и продемонстрировано в этом ответе - String.format()и Formatterклассы в JDK являются лучшими вариантами. Используйте их поверх общего кода.

GaryF
источник
91
java.util.Formatter (и String.format ()) делает это. Всегда предпочитайте JDK внешней библиотеке, если версия JDK выполняет свою работу (что она и делает).
Клет
6
По нескольким причинам я бы сейчас предпочел Guava Apache Commons; Этот ответ показывает, как это сделать в Гуаве .
Джоник
1
@Jonik Не могли бы вы перечислить некоторые из ваших причин? API выглядят практически одинаково.
glen3b
3
@ glen3b: Для отдельной утилиты, такой как эти помощники заполнения строк, действительно не имеет значения, какую библиотеку использовать. Тем не менее, Guava в целом является более современной, более чистой и лучше документированной библиотекой, чем ее аналоги в различных проектах Apache Commons (Commons Lang, Commons Collections, Commons IO и т. Д.). Он также построен по-настоящему умными парнями (Кевин Бурриллион и др.), Многие из которых работают в SO . Я сам закончил тем, что заменил различные библиотеки Apache Commons только на Guava несколько лет назад, и не пожалел.
Джоник
3
@ glen3b: Хорошего дальнейшего чтения по этому вопросу .
Джоник
635

Начиная с 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*
RealHowTo
источник
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$и он, очевидно, имеет тот же эффект. Есть ли разница?
Фабрисио Мате
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(" (?=( |$))", "*")
Ярослав Павляк
88

В Гуаве это легко:

Strings.padStart("string", 10, ' ');
Strings.padEnd("string", 10, ' ');
Гарретт Холл
источник
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? Форматировщик выдает, FormatFlagsConversionMismatchExceptionкогда %0sэто строка формата.
Девин Уолтерс
7

Это заняло у меня некоторое время, чтобы понять. Настоящим ключом является чтение этой документации Formatter.

// 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);
Nthalk
источник
Зачем делать конец так сложно? Вы могли просто сделать String hex = String.format ("% 032x", дайджест); и имели те же самые результаты, только без ненужной replace () и необходимости использовать $ для доступа к определенным переменным (в конце концов, есть только одна.)
ArtOfWarfare
@ArtOfWarfare Fair point. Кто-то изначально просил заполнить шестнадцатеричные значения в другом вопросе, я увидел, что у меня есть ссылка на документацию по форматированию. Это сложно для полноты.
Nthalk
6

я знаю, что эта ветка довольно старая, и первоначальный вопрос был для простого решения, но если он должен быть очень быстрым, вы должны использовать массив символов.

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-------";
fawsha1
источник
5

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

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

Вывод:

*****apple
apple*****
Эко Сетаван
источник
1
Лучший ответ для Java 11!
Надя Аттила
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(...)метода. В этом случае выполните настройку скрытого заполнения в этом методе, а не в конструкторе.

(Подсказка: для дополнительного кредита, сделайте это поточно-ориентированным! ;-)

joel.neely
источник
1
Это потокобезопасно, за исключением небезопасной публикации (сделайте ваши поля окончательными, как само собой разумеющееся). Я думаю, что производительность можно улучшить, выполнив подстроку перед +, которую следует заменить на concat (как ни странно).
Том Хотин - tackline
3

Нашел это на Dzone

Накладка с нулями:

String.format("|%020d|", 93); // prints: |00000000000000000093|
OJVM
источник
Это должен быть ответ, простой и лаконичный, не нужно устанавливать внешние библиотеки.
Вонг Цзя Хау
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());
ef_oren
источник
2

Это работает:

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

Это заполнит вашу строку 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

Позвольте мне оставить ответ для некоторых случаев, когда вам нужно задать левый / правый отступ (или строку префикса / суффикса, или пробелы) перед тем, как объединить другую строку, и вы не хотите проверять длину или любое условие if.

То же самое к выбранному ответу, я бы предпочел StringUtilsApache Commons, но используя этот способ:

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

Объясните:

  • myString: строка, которую я ввожу, может быть нулевой
  • StringUtils.leftPad(myString, 1): если строка равна нулю, этот оператор также будет возвращать ноль
  • затем используйте, defaultStringчтобы дать пустую строку, чтобы предотвратить конкатенацию ноль
Osify
источник
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 
ndm13
источник
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сделаю левый и правый отступ. Нет необходимости в нечетных сторонних зависимостях (вы хотите добавить их для чего-то такого тривиального).

[Я упустил детали и сделал этот пост «вики-сообществом», так как он мне не нужен.]

Том Хотин - Tackline
источник
4
Я не согласен. В любом более крупном Java-проекте вы, как правило, будете выполнять так много манипуляций со строками, что повышение читабельности и избежание ошибок стоит использовать 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 ((char [])). Причина этого в том, что если вы применяете несколько операций, вы можете выполнять их все на char [] и не продолжать конвертацию между форматами - за кулисами String сохраняется как char []. Если бы эти операции были включены в сам класс String, он был бы в два раза эффективнее - по скорости и по памяти.
EarlB
источник
Это действительно выглядит наиболее эффективным способом
Дэвид Лилльгегрен
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();
}
Aelphaeis
источник
2
Это очень неэффективно, вы должны использовать
StringBuilder
Поскольку вы уже знаете длину, вы должны указать StringBuilder выделить столько места при его создании.
Ариэль
@ Ариэль интересно, что ты упомянул это, потому что я только что говорил с кем-то об этом сегодня, смеется.
Элфэйс
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 Left, не ограничивать

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

Pad Right, не ограничивайте

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

Pad Left, ограничение по длине площадки

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

Pad Right, ограничение длины площадки

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);
        }
    }

ПРИМЕЧАНИЕ . Это решение добавит заполнение, с небольшим изменением, которое вы можете добавить к значению дополнения.

Saikat
источник
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

Примеры заполнения в Гуаве:

Примеры заполнения в Apache Commons:

Примеры заполнения в JDK:

APISonar
источник
-1

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

package nl;
public class Padder {
    public static void main(String[] args) {
        String s = "123" ;
        System.out.println("#"+("     " + s).substring(s.length())+"#");
    }
}
Ханс Андевег
источник
-1

Как это

Строка "hello" и требуемый отступ равен 15 с "0" left pad

String ax="Hello";
while(ax.length() < 15) ax="0"+ax;
Satwant
источник
10
этот генерирует до 15 новых строк.
Claj
@claj Да, но это .
Ерф