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


432

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

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


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

Ответы:


189

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

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


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 несколько лет назад, и не пожалел.
Джоник


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*

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(" (?=( |$))", "*")
Ярослав Павляк


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

Зачем делать конец так сложно? Вы могли просто сделать 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-------";

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(...)метода. В этом случае выполните настройку скрытого заполнения в этом методе, а не в конструкторе.

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


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

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")

Это заполнит вашу строку 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чтобы дать пустую строку, чтобы предотвратить конкатенацию ноль

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-проекте вы, как правило, будете выполнять так много манипуляций со строками, что повышение читабельности и избежание ошибок стоит использовать 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, он был бы в два раза эффективнее - по скорости и по памяти.

Это действительно выглядит наиболее эффективным способом
Дэвид Лилльгегрен

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

Поскольку вы уже знаете длину, вы должны указать 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);
        }
    }

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


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

Как это

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

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

10
этот генерирует до 15 новых строк.
Claj

@claj Да, но это .
Ерф
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.