N karakterli bir dize oluşturma


144

Java'da belirtilen sayıda belirtilen karaktere sahip bir dize oluşturmanın bir yolu var mı? Benim durumumda, 10 boşluklu bir dize oluşturmak gerekir. Geçerli kodum:

StringBuffer outputBuffer = new StringBuffer(length);
for (int i = 0; i < length; i++){
   outputBuffer.append(" ");
}
return outputBuffer.toString();

Aynı şeyi başarmanın daha iyi bir yolu var mı? Özellikle hızlı (idam açısından) bir şey rica ediyorum.


1
Kendinizi çok fazla yaparsanız, bir işlev yazın: String characterRepeat (Char c, int Length) {...}, herhangi bir karakter ve herhangi bir uzunluk için orada ne yaptığınızı yapar. O zaman sadece ihtiyacınız olduğunda arayın.
Austin Fitzpatrick

12
StringBuffer yerine StringBuilder kullanmak istiyorsunuz

Tampon büyüklüğünün başlangıcında ekleyin, hesaplamak kolaydır bellek yönetimi bir şeyler kolaylaştırır !. StringBuilder outputBuffer = new StringBuilder (repeat * base.length ());
Victor


Tek bir boşluk eklemek istiyorsanız, append(' ')bunun yerine kullanın ... biraz daha az bilgi işlem gerektirir ...
Erk

Yanıtlar:


36

For döngüsü derleyici tarafından optimize edilir. Sizinki gibi durumlarda, optimizasyonu tek başınıza yapmanız gerekmez. Derleyiciye güvenin.

BTW, n boşluk karakterli bir dize oluşturmanın bir yolu varsa, tıpkı sizin yaptığınız gibi kodlandığından daha fazladır.


1
optimize edilmemiş olsa bile - bu programınızda ne sıklıkta oluşturulur - genellikle statik bir değişkene veya başka bir önbelleğe kaydediliyorsa
mmmmmm

btw Array.fill () sadece dizi içinde dolaşır. / me diğerleri mesajlar hakkında yorum yapmak için kesinlikle daha fazla puana ihtiyacım var :)
kalkin

@Mark Uzunluğu değişkendir, bu yüzden kaydetmek aptalca görünür. Ne yapmam gerekir static Dictionary<int, String>?
C. Ross

1
Dize isteyeceğiniz en uzun " ".substring(0, 10);
saklayın

169

StringAPI'yi kullanan muhtemelen en kısa kod :

String space10 = new String(new char[10]).replace('\0', ' ');

System.out.println("[" + space10 + "]");
// prints "[          ]"

Bir yöntem olarak, doğrudan somutlaştırmadan char:

import java.nio.CharBuffer;

/**
 * Creates a string of spaces that is 'spaces' spaces long.
 *
 * @param spaces The number of spaces to add to the string.
 */
public String spaces( int spaces ) {
  return CharBuffer.allocate( spaces ).toString().replace( '\0', ' ' );
}

Şunu kullanarak çağır:

System.out.printf( "[%s]%n", spaces( 10 ) );

4
Tek astarı sevmeme rağmen, FrustratedWithFormsDes'in çözümünün yürütme söz konusu olduğunda daha iyi olduğunu düşünüyorum çünkü her biri \ 0 için kontrol etmekten kaçınır ve sadece alanı atar.
Bouncner

1
Test edildi, bu her zaman döngüden daha hızlı, oldukça tutarlı bir şekilde 50000-100000 nano saniye daha hızlı, bu da toplam süre hala yüksek olmasına rağmen yineleme sayısı arttıkça döngü daha hızlı hale gelebilir (0.1 milisaniye). Bu, farklı boyutlarda boşluk dizeleri oluştururken geçerlidir.
kmecpp

Oldukça güzel bir çözüm için yumruk atıyorum, cevabımı burada kullandım stackoverflow.com/questions/852665/…
maytham-ɯɐɥʇʎɐɯ

66

Hmm şimdi düşünüyorum, belki Arrays.fill:

char[] charArray = new char[length];
Arrays.fill(charArray, ' ');
String str = new String(charArray);

Tabii ki, fillyöntemin kodunuzla aynı şeyi yaptığını varsayıyorum , bu yüzden muhtemelen yaklaşık aynı performansı gösterecektir, ancak en azından bu daha az satırdır.


2
Kaynağını kontrol ettikten sonra, OP yayınlanmıştır tam olarak ne aslında yaptığı görünüyor: çizgi arasında 806 docjar.com/html/api/java/util/Arrays.java.html
Pops

2
@Lord Torgamus OP'nin sorusu düzenlendi mi? Çünkü gördüğüm sürümde, StringBuffer.append () üzerinde döngü ve Frustrated'ın sürümü bir dolgu yapıyor (tabii ki diziye char atamaları yapıyor döngüler). Aynı şey değil.
CPerkins

@CPerkins, yeterince adil, net değildim. Demek istediğim, her ikisi de bir for döngüsünün içine karakter karakter ekleme yapıyor.
Pops

1
@Lord Torgamus - Buna katıldım. yazık ki jvm sadece bir memset yapamaz. Geniş karakterler için ödediğimiz fiyat.
CPerkins

2
@Pops, Arrays.fill()işlev bu işi kodunuzda ve (standart ve harici) kütüphane kodunda sürekli olarak kullanmak için kullanıldığında , Hotspot derlemesi için iyi bir aday olduğunu ve CPU önbelleğinizi bulma şansının daha yüksek olduğunu belirtmek gerekir. Gelecekteki JVM'ler bunu içsel bir işlev olarak atayabilir . Kendinizi yuvarlamak, tüm bu performans iyiliğinden sizi keser ...
SusanW

65

Döngüyü elle yazmamanızı şiddetle tavsiye ederim. Programlama kariyeriniz boyunca bunu tekrar tekrar yapacaksınız. Kodunuzu okuyan - sizi de içeren insanlar - sadece birkaç saniye olsa bile, döngünün anlamını sindirmek için zaman harcamak zorundadır.

Bunun yerine , Apache Commons Lang'da olduğu gibi kod sağlayan mevcut kitaplıklardan birini yeniden kullanın :StringUtils.repeat

StringUtils.repeat(' ', length);

Bu şekilde performansla uğraşmak zorunda kalmazsınız, bu nedenle StringBuilderDerleyici optimizasyonları vb. Eğer fonksiyon yavaşça ortaya çıkarsa kütüphane hatası olur.

Java 11 ile daha da kolaylaşır:

" ".repeat(length);

5
Öte yandan, eğer StringUtils zaten projede kullanılmıyorsa, böyle basit bir görev için başka bir bağımlılık eklemek aşırıya kaçma olabilir.
Erich Kitzmueller

1
yavaşladıysa, işlev için kendi düzeltmenizi de gönderebilirsiniz.
olacak

26

Java 8'de şunları kullanabilirsiniz String.join:

String.join("", Collections.nCopies(n, s));

13

Sadece boşluk istiyorsanız, o zaman:

String spaces = (n==0)?"":String.format("%"+n+"s", "");

abs (n) boşlukları ile sonuçlanacak;


6
Hız için bu nasıl? Ben izlenim biçimi altında nispeten yavaş. Ne de olsa onu oluşturmak için önce dizeyi ayrıştırmak zorundadır.
C. Ross

11

Java 11'den beri :

" ".repeat(10);

Java 8'den beri :

generate(() -> " ").limit(10).collect(joining());

nerede:

import static java.util.stream.Collectors.joining;
import static java.util.stream.Stream.generate;

9

Java 11'den beri String.repeat(count)sorununuzu çözmek için kullanabilirsiniz .

Değeri bu dizenin tekrarlanan countkez birleşimi olan bir dize döndürür .

Bu dize boşsa veya countsıfırsa, boş dize döndürülür.

Yani bir döngü yerine kodunuz şöyle görünecektir:

" ".repeat(length);

8

Bu mümkün daha az kod olduğunu düşünüyorum, Guava Joiner sınıfı kullanır:

Joiner .on (""). Join ( Collections.nCopies (10, ""));


En kısa kod satırı ancak bu basit görev için büyük bir kütüphane eklemek mantıklı değil. Ben pubic String n(int n) { ... }bile daha az "kod" izin verecek tek bir yöntemle kendim küçük bir JAR oluşturabilir : n(10)ama yine, hiçbir mantıklı değil.
isapir

@isapir Bu, zaten Guava kullanan insanlar için harika bir cevap
nasch

1
@nasch Guava sorunun bir parçası değildi. Her neyse, 2018'de Java 8'de eklenen String.join () kullanabileceğiniz Guava's Joiner'ı kullanmanız için hiçbir neden yoktur. Bkz. Stackoverflow.com/a/43011939/968244
isapir

@isapir Hayır, Guava bir cevaptı. StackOverflow'daki yanıtlar, yalnızca soruyu soran kişiden daha geniş bir kitleye sahiptir, bu nedenle, bazı yanıtlar soran kişi için en iyisi değilse sorun yoktur. Ve String.join () ile ilgili yorum harika bir şey olsa da, Android'in tüm sürümlerinde mevcut olup olmadığından emin değilim, bu da Java'nın önemli bir kullanımıdır.
nasch

7

String.formatN boşluk oluşturmak için standart işlevi kullanabilirsiniz . Örneğin:

String.format("%5c", ' ');

5 boşluklu bir dize oluşturur.

veya

int count = 15;
String fifteenSpacebars = String.format("%" + count + "c", ' ');

15 ara çubuğu dizesi yapar.

Başka bir sembolün tekrarlanmasını istiyorsanız, boşlukları istediğiniz sembolle değiştirmeniz gerekir:

int count = 7;
char mySymbol = '#';
System.out.println(String.format("%" + count + "c", ' ').replaceAll("\\ ", "\\" + mySymbol));

Çıktı:

#######

6

Katkılarım hızlı üs alma algoritmasına dayanıyor.

/**
 * Repeats the given {@link String} n times.
 * 
 * @param str
 *            the {@link String} to repeat.
 * @param n
 *            the repetition count.
 * @throws IllegalArgumentException
 *             when the given repetition count is smaller than zero.
 * @return the given {@link String} repeated n times.
 */
public static String repeat(String str, int n) {
    if (n < 0)
        throw new IllegalArgumentException(
                "the given repetition count is smaller than zero!");
    else if (n == 0)
        return "";
    else if (n == 1)
        return str;
    else if (n % 2 == 0) {
        String s = repeat(str, n / 2);
        return s.concat(s);
    } else
        return str.concat(repeat(str, n - 1));
}

Algoritmayı diğer iki yaklaşıma karşı test ettim:

  • String.concat()Dizeyi bitiştirirken döngü kullanımı için düzenli
  • Bir kullanarak döngü için düzenli StringBuilder

Test kodu (for döngüsü kullanarak birleştirme ve String.concat()büyük için yavaş olur n, bu yüzden 5. yinelemeden sonra dışarıda bıraktım).

/**
 * Test the string concatenation operation.
 * 
 * @param args
 */
public static void main(String[] args) {
    long startTime;
    String str = " ";

    int n = 1;
    for (int j = 0; j < 9; ++j) {
        n *= 10;
        System.out.format("Performing test with n=%d\n", n);

        startTime = System.currentTimeMillis();
        StringUtil.repeat(str, n);
        System.out
                .format("\tStringUtil.repeat() concatenation performed in    %d milliseconds\n",
                        System.currentTimeMillis() - startTime);

        if (j <5) {
            startTime = System.currentTimeMillis();
            String string = "";
            for (int i = 0; i < n; ++i)
                string = string.concat(str);
            System.out
                    .format("\tString.concat() concatenation performed in        %d milliseconds\n",
                            System.currentTimeMillis() - startTime);
        } else
            System.out
                    .format("\tString.concat() concatenation performed in        x milliseconds\n");
        startTime = System.currentTimeMillis();
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < n; ++i)
            b.append(str);
        b.toString();
        System.out
                .format("\tStringBuilder.append() concatenation performed in %d milliseconds\n",
                        System.currentTimeMillis() - startTime);
    }
}

Sonuçlar:

Performing test with n=10
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        0 milliseconds
    StringBuilder.append() concatenation performed in 0 milliseconds
Performing test with n=100
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        1 milliseconds
    StringBuilder.append() concatenation performed in 0 milliseconds
Performing test with n=1000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        1 milliseconds
    StringBuilder.append() concatenation performed in 1 milliseconds
Performing test with n=10000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        43 milliseconds
    StringBuilder.append() concatenation performed in 5 milliseconds
Performing test with n=100000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        1579 milliseconds
    StringBuilder.append() concatenation performed in 1 milliseconds
Performing test with n=1000000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 10 milliseconds
Performing test with n=10000000
    StringUtil.repeat() concatenation performed in    7 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 112 milliseconds
Performing test with n=100000000
    StringUtil.repeat() concatenation performed in    80 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 1107 milliseconds
Performing test with n=1000000000
    StringUtil.repeat() concatenation performed in    1372 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 12125 milliseconds

Sonuç:

  • Büyük için n- özyinelemeli yaklaşımı kullanın
  • Küçük için n- döngü için yeterli hız var

4
Bu ilginç bir uygulama. Ne yazık ki, sonuçlarınızın aksine, büyük n için çok verimsizdir. Bunun, dizeleri her birleştirdiğinizde devam eden birçok bellek ayırması nedeniyle olduğundan şüpheleniyorum. String yerine StringBuilder alan bir özyinelemeli yöntem çevresinde bir sarmalayıcı olarak yazmayı deneyin. Eminim sonuçların çok daha iyi olacağını göreceksiniz.
Klitos Kyriacou

3
Böyle bir şeyi mikro-kıyaslama yaparken almanız gereken birçok önlem var ve bunlardan herhangi birini aldığınızı sanmıyorum! Bu kod etrafında baskın performans soruları kolayca Hotspot derlenmiş olup olmadığını, ne kadar çöp oluşturur, vb olabilir. Ben tüm bu ififadeler CPU şube tahmin berbat olacak bahis . Bu gerçekten JMH ( openjdk.java.net/projects/code-tools/jmh ) kullanılarak yeniden yapılmalıdır , aksi takdirde biraz anlamsızdır.
SusanW

Bu uygulamanın O (n * log n) karmaşıklığına sahip olduğunu, StringBuilder ise O (n) :)
Leo Leontev


4

Elimizde:

String c = "c"; // character to repeat, for empty it would be " ";
int n = 4; // number of times to repeat
String EMPTY_STRING = ""; // empty string (can be put in utility class)

Java 8 (Akışı Kullanma)

String resultOne = IntStream.range(0,n)
   .mapToObj(i->c).collect(Collectors.joining(EMPTY_STRING)); // cccc

Java 8 (nCopies Kullanarak)

String resultTwo = String.join(EMPTY_STRING, Collections.nCopies(n, c)); //cccc

1
Collectors.joining(EMPTY_STRING)eşdeğerCollectors.joining()
PPartisan

2

RandomStringUtils , belirtilen girdi boyutundan bir dize oluşturma özelliğine sahiptir. Hız yorum yapamam, ama onun bir astar.

RandomStringUtils.random(5,"\t");

çıktı oluşturur

\ \ T \ t \ t \ t

kodunuzda \ 0 görmek istemiyorsanız tercih edilir .



1

Çoğu durumda, 100 boşluk gibi belirli bir uzunluktaki dizelere ihtiyacınız vardır. Dizin sayısının boşlukla doldurulmuş dizenin boyutuna eşit olduğu bir Dizeler dizisi hazırlayabilir ve gerekli uzunluk sınırlar dahilindeyse dizeyi arayabilir veya sınırın dışındaysa istek üzerine oluşturabilirsiniz.



0

StringBuffer'ınızı bir StringBuilder ile değiştirin . Bunu yenmek zor.

Uzunluğunuz büyük bir sayı ise, her bir yinelemede uzunluğu çoğaltarak daha verimli (ancak daha sakar) kendi kendine ekleme uygulayabilirsiniz:

 public static String dummyString(char c, int len) {
  if( len < 1 ) return "";
  StringBuilder sb = new StringBuilder(len).append(c);
  int remnant = len - sb.length();
  while(remnant  > 0) {
   if( remnant  >= sb.length() ) sb.append(sb);
   else sb.append(sb.subSequence(0, remnant));
   remnant  = len - sb.length();
  }
  return sb.toString();
 }

Ayrıca, Arrays.fill()yaklaşımı deneyebilirsiniz ( FrustratedWithFormsDesigner'ın yanıtı).


Bazı değişkenleri birden fazla karakter olarak adlandırabilir misiniz?
C. Ross

0

Sen yerini alabilir StringBufferile StringBuilder(ikincisi senkronize edilmedi; daha hızlı bir tek iplik uygulamasında olabilir)

Ve oluşturabileceğiniz StringBuilderyerine Eğer ihtiyacınız her zaman yaratma, bir kez örneği.

Bunun gibi bir şey:

class BuildString {
     private final StringBuilder builder = new StringBuilder();
     public String stringOf( char c , int times ) {

         for( int i = 0 ; i < times ; i++  ) {
             builder.append( c );
         }
         String result = builder.toString();
         builder.delete( 0 , builder.length() -1 );
         return result;
      }

  }

Ve şu şekilde kullanın:

 BuildString createA = new BuildString();
 String empty = createA.stringOf( ' ', 10 );

Öğenizi createAörnek değişkeni olarak tutarsanız, örnek oluştururken zaman kazanabilirsiniz.

Bu iş parçacığı için güvenli değildir, çoklu iş parçacıklarınız varsa, her iş parçacığının kendi kopyası olmalıdır.


0

İyi performans için aznilamir ve FrustratedWithFormsDesigner'ın yanıtlarını birleştirin

private static final String BLANKS = "                       ";
private static String getBlankLine( int length )
{
    if( length <= BLANKS.length() )
    {
        return BLANKS.substring( 0, length );
    }
    else
    {
        char[] array = new char[ length ];
        Arrays.fill( array, ' ' );
        return new String( array );
    }
}

BLANKSİhtiyaçlarınıza göre boyutunu ayarlayın . Özel BLANKSdizem yaklaşık 200 karakter uzunluğunda.


0

Böyle bir yöntem var. Bu , belirli bir uzunlukta uzunluk Stringvermek için verilenin sonuna gerekli boşlukları ekler String.

public static String fillSpaces (String str) {

    // the spaces string should contain spaces exceeding the max needed
    String spaces = "                                                   ";
    return str + spaces.substring(str.length());
}

0

Dize'nin sabit boyutta olmasını istediğinizden, verileri tablolamak için ped veya kısaltmayı kullanın ...

class Playground {
    private static String fixStrSize(String s, int n) {
        return String.format("%-" + n + "s", String.format("%." + n +"s", s));
    }

    public static void main(String[ ] args) {
        System.out.println("|"+fixStrSize("Hell",8)+"|");
        System.out.println("|"+fixStrSize("Hells Bells Java Smells",8)+"|");
    }
}

|Hell    |
|Hells Be|

Mükemmel referans burada .


0

Bu, Java 8'de herhangi bir harici kitaplık kullanmadan benim için çalıştı

String sampleText = "test"
int n = 3;
String output = String.join("", Collections.nCopies(n, sampleText));
System.out.println(output);

Ve çıktı

testtesttest

0

int c = 10; Dize boşlukları = String.format ("%" + c + "c", ''); Bu sorununu çözecektir.


-1

Aşağıdaki gibi basit bir yöntem de kullanılabilir

public static String padString(String str, int leng,char chr) {
        for (int i = str.length(); i <= leng; i++)
            str += chr;
        return str;
    }

Bu çok daha yavaştır.
SLaks

Karşılaştığınız dizelerin büyük boyutta olması durumunda, dize birleştirmesi yerine StringBuffer kullanabilirsiniz. Bu, hızı önemli ölçüde etkileyecektir
Yashpal Singla 29:13

-2

buna ne dersin?

public String fillSpaces(int len) {
    /* the spaces string should contain spaces exceeding the max needed */  
    String spaces = "                                                   ";
    return spaces.substring(0,len);
}

EDIT: Ben kavram ve burada ne buldum test etmek için basit bir kod yazdım.

Yöntem 1: bir döngüde tek boşluk ekleme:

  public String execLoopSingleSpace(int len){
    StringBuilder sb = new StringBuilder();

    for(int i=0; i < len; i++) {
        sb.append(' ');
    }

    return sb.toString();
  }

Yöntem 2: 100 boşluk ve döngü ekleyin, ardından alt dize:

  public String execLoopHundredSpaces(int len){
    StringBuilder sb = new StringBuilder("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ");

    for (int i=0; i < len/100 ; i++) {
        sb.append("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ");
    }

    return sb.toString().substring(0,len);
  }

12.345.678 boşluk oluşturduğum sonuç:

C:\docs\Projects> java FillSpace 12345678
method 1: append single spaces for 12345678 times. Time taken is **234ms**. Length of String is 12345678
method 2: append 100 spaces for 123456 times. Time taken is **141ms**. Length of String is 12345678
Process java exited with code 0

ve 10.000.000 alan için:

C:\docs\Projects> java FillSpace 10000000
method 1: append single spaces for 10000000 times. Time taken is **157ms**. Length of String is 10000000
method 2: append 100 spaces for 100000 times. Time taken is **109ms**. Length of String is 10000000
Process java exited with code 0

Doğrudan ayırma ve yinelemeyi birleştirmek, büyük alanlar oluştururken her zaman daha az zaman, ortalama 60 ms daha az zaman alır. Daha küçük boyutlar için her iki sonuç da ihmal edilebilir.

Ama lütfen yorum yapmaya devam edin :-)


3
@ aznilamir: Hm, 10 bin uzay için nasıl yapacaksın?
Jayan

Fikir, 100 alanın döngü ve doğrudan tahsisini birleştirmektir. İşte kod parçacıkları:
aznilamir

100 karakter eklemek için neden birden çok ek kullanıyorsunuz? Neden 100 karakter eklenmiyor?
nycynik

-3

Sorduğunuz şey için yerleşik bir yöntem bilmiyorum. Bununla birlikte, 10 gibi küçük bir sabit uzunluk için, yönteminiz çok hızlı olmalıdır.


Sadece 10 gibi küçük bir sabit uzunluk olsaydı.
C. Ross
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.