Buat string dengan n karakter


144

Apakah ada cara di java untuk membuat string dengan jumlah karakter yang ditentukan? Dalam kasus saya, saya perlu membuat string dengan 10 spasi. Kode saya saat ini adalah:

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

Apakah ada cara yang lebih baik untuk mencapai hal yang sama. Khususnya saya suka sesuatu yang cepat (dalam hal eksekusi).


1
Jika Anda sering melakukannya, cukup tulis fungsi: String characterRepeat (Char c, int Length) {...} yang melakukan apa yang Anda lakukan di sana untuk setiap karakter dan panjang apa pun. Kemudian panggil saja saat Anda membutuhkannya.
Austin Fitzpatrick

12
Anda ingin menggunakan StringBuilder alih-alih StringBuffer

Tambahkan pada awal ukuran buffer, mudah untuk menghitung dan memfasilitasi hal-hal dalam manajemen memori !. StringBuilder outputBuffer = StringBuilder baru (ulangi * base.length ());
Victor


Jika Anda ingin menambahkan satu ruang, gunakan append(' ')saja ... ini melibatkan komputasi yang sedikit lebih sedikit ...
Erk

Jawaban:


36

For loop akan dioptimalkan oleh kompiler. Dalam kasus seperti ini, Anda tidak perlu peduli tentang pengoptimalan sendiri. Percayai kompiler.

BTW, jika ada cara untuk membuat string dengan karakter n spasi, daripada dikodekan dengan cara yang sama seperti yang baru saja Anda lakukan.


1
bahkan jika ini tidak dioptimalkan - seberapa sering ini dibuat dalam program Anda - jika sering menyimpan dalam variabel statis atau cache lainnya
mmmmmm

btw Array.fill () hanya loop melalui array. / saya perlu lebih banyak poin untuk mengomentari pos orang lain :)
kalkin

@Mark Length adalah variabel, jadi sepertinya konyol untuk menyimpannya. Apa yang akan saya lakukan, miliki static Dictionary<int, String>?
C. Ross

1
Simpan paling lama yang Anda inginkan, kemudian gunakan sesuatu seperti ini: " ".substring(0, 10);
mjaggard

169

Kemungkinan kode terpendek menggunakan StringAPI, secara eksklusif:

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

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

Sebagai metode, tanpa langsung membuat contoh 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', ' ' );
}

Meminta menggunakan:

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

4
Meskipun saya suka one-liner, saya pikir solusi FrustratedWithFormsDes adalah yang lebih baik ketika datang ke eksekusi karena menghindari memeriksa masing-masing untuk \ 0 dan hanya menetapkan ruang.
Bouncner

1
Diuji, ini selalu lebih cepat daripada loop, cukup konsisten 50000-100000 nano detik lebih cepat, yang bisa sangat signifikan (0,1 milidetik) loop memang semakin cepat karena jumlah iterasi meningkat meskipun total waktu masih tinggi. Ini berlaku untuk saat membuat ukuran string ruang yang berbeda.
kmecpp

Buk untuk solusi yang cukup bagus, saya telah menggunakannya dalam jawaban saya di sini stackoverflow.com/questions/852665/…
maytham-ɯɐɥʇʎɐɯ

66

Hmm sekarang saya memikirkannya, mungkin Arrays.fill:

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

Tentu saja, saya berasumsi bahwa fillmetode ini melakukan hal yang sama dengan kode Anda, jadi mungkin akan melakukan hal yang sama, tetapi setidaknya ini lebih sedikit baris.


2
Setelah memeriksa sumbernya, tampaknya ini benar-benar melakukan persis apa yang diposting oleh OP: baris 806 dari docjar.com/html/api/java/util/Arrays.java.html
Pops

2
@ Lord Torgamus Apakah pertanyaan OP diedit? Karena dalam versi yang saya lihat, dia mengulangi pada StringBuffer.append (), dan versi Frustrated sedang mengisi (yang tentu saja loop melakukan tugas char ke array). Bukan hal yang sama sekali.
CPerkins

@CPerkins, cukup adil, saya tidak jelas. Maksud saya adalah keduanya melakukan penyisipan karakter per karakter di dalam for for.
Pops

1
@ Lord Torgamus - Menyetujui hal itu. Sayang jvm tidak bisa hanya melakukan memset. Harga yang kami bayar untuk karakter lebar.
CPerkins

2
@ Pops perlu dicatat bahwa jika Arrays.fill()fungsi ini digunakan secara konsisten untuk melakukan pekerjaan ini di kode Anda dan kode perpustakaan (standar dan eksternal), maka itu membuat kandidat yang baik untuk kompilasi Hotspot, dan memiliki peluang lebih besar untuk ditemukan cache CPU Anda. JVM masa depan dapat menetapkannya sebagai fungsi intrinsik . Menggulung Anda sendiri memotong Anda dari semua kebaikan kinerja ini ...
SusanW

65

Saya sangat menyarankan untuk tidak menulis loop dengan tangan. Anda akan melakukannya berulang kali selama karir pemrograman Anda. Orang-orang yang membaca kode Anda - termasuk Anda - selalu harus menginvestasikan waktu, meskipun hanya beberapa detik, untuk mencerna makna dari loop tersebut.

Alih-alih menggunakan kembali salah satu pustaka yang tersedia yang menyediakan kode seperti itu StringUtils.repeatdari Apache Commons Lang :

StringUtils.repeat(' ', length);

Dengan begitu Anda juga tidak perlu repot tentang kinerja, sehingga semua detail mengerikan StringBuilder, optimisasi Kompiler dll. Disembunyikan. Jika fungsinya akan menjadi lambat itu akan menjadi bug dari perpustakaan.

Dengan Java 11 menjadi lebih mudah:

" ".repeat(length);

5
Di sisi lain, jika StringUtils belum digunakan dalam proyek, menambahkan ketergantungan lain untuk tugas sederhana seperti itu mungkin merupakan kerja keras.
Erich Kitzmueller

1
jika ternyata lambat, Anda juga dapat mengirimkan perbaikan sendiri untuk fungsi tersebut.
akan


13

Jika Anda hanya ingin spasi, lalu bagaimana:

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

yang akan menghasilkan abs (n) spasi;


6
Bagaimana itu untuk kecepatan? Saya di bawah format tayangan yang relatif lambat. Itu harus mengurai string sebelum dapat membuatnya setelah semua.
C. Ross

11

sejak Jawa 11 :

" ".repeat(10);

sejak Java 8 :

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

dimana:

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

9

Karena Java 11, Anda cukup menggunakan String.repeat(count)untuk menyelesaikan masalah Anda.

Mengembalikan string yang nilainya merupakan rangkaian string ini diulangi count kali.

Jika string ini kosong atau countnol maka string kosong dikembalikan.

Jadi alih-alih loop, kode Anda hanya akan terlihat seperti ini:

" ".repeat(length);

8

Saya pikir ini adalah kode yang kurang mungkin, menggunakan kelas Guava Joiner:

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


Baris kode terpendek tetapi menambahkan perpustakaan besar hanya untuk tugas sederhana itu tidak masuk akal. Saya dapat membuat JAR yang lebih kecil sendiri dengan metode tunggal pubic String n(int n) { ... }yang akan memungkinkan kode "kurang":, n(10)tapi sekali lagi, tidak masuk akal.
isapir

@isapir Ini adalah jawaban yang bagus untuk orang-orang yang sudah menggunakan Jambu Biji
nasch

1
@nasch Guava bukan bagian dari pertanyaan. Tapi bagaimanapun, pada tahun 2018 benar-benar tidak ada alasan untuk menggunakan Guava's Joiner ketika Anda dapat menggunakan String.join () yang ditambahkan di Jawa 8. Lihat stackoverflow.com/a/43011939/968244
isapir

@ mengisapir Tidak, Jambu adalah jawaban. Jawaban di StackOverflow memiliki audiens yang lebih luas daripada hanya orang yang mengajukan pertanyaan, jadi tidak apa-apa jika beberapa jawaban bukan yang terbaik untuk orang yang bertanya. Dan komentar tentang String.join () adalah yang hebat meskipun saya tidak yakin apakah itu tersedia di semua versi Android, yang merupakan penggunaan Java yang menonjol.
nasch

7

Anda dapat menggunakan String.formatfungsi standar untuk menghasilkan spasi N. Sebagai contoh:

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

Membuat string dengan 5 spasi.

atau

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

Membuat string 15 spacebars.

Jika Anda ingin simbol lain diulang, Anda harus mengganti spasi dengan simbol yang Anda inginkan:

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

Keluaran:

#######

6

Kontribusi saya berdasarkan algoritma eksponensial cepat.

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

Saya menguji algoritma terhadap dua pendekatan lain:

  • Biasa untuk loop menggunakan String.concat()untuk menyatukan string
  • Biasa untuk loop menggunakan a StringBuilder

Kode uji (gabungan menggunakan for loop dan String.concat()menjadi lambat untuk besar n, jadi saya meninggalkannya setelah iterasi ke-5).

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

Hasil:

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

Kesimpulan:

  • Untuk yang besar n- gunakan pendekatan rekursif
  • Untuk kecil n- untuk loop memiliki kecepatan yang cukup

4
Ini implementasi yang menarik. Sayangnya, bertentangan dengan kesimpulan Anda, itu sangat tidak efisien untuk n besar. Saya menduga ini karena banyak alokasi memori yang terjadi setiap kali Anda menggabungkan string. Cobalah menulisnya sebagai pembungkus di sekitar metode rekursif yang mengambil StringBuilder, bukan String. Saya yakin Anda akan menemukan hasilnya akan jauh lebih baik.
Klitos Kyriacou

3
Ada banyak tindakan pencegahan yang perlu Anda ambil ketika melakukan benchmarking mikro seperti ini, dan saya rasa Anda tidak mengambil salah satu dari mereka! Pertanyaan kinerja yang dominan di sekitar kode ini bisa dengan mudah adalah apakah itu dikompilasi dengan Hotspot, berapa banyak sampah yang dihasilkannya, dll. Saya yakin semua ifpernyataan itu akan mengacaukan prediksi cabang CPU. Ini harus benar-benar diulangi menggunakan JMH ( openjdk.java.net/projects/code-tools/jmh ), jika tidak, ini agak tidak berguna.
SusanW

Perhatikan bahwa implementasi ini memiliki kompleksitas O (n * log n), sementara StringBuilder adalah O (n) :)
Leo Leontev


4

Mengingat kami memiliki:

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 (Menggunakan Stream)

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

Java 8 (Menggunakan nCopies)

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

1
Collectors.joining(EMPTY_STRING)setara denganCollectors.joining()
PPartisan

2

RandomStringUtils memiliki ketentuan untuk membuat string dari ukuran input yang diberikan. Tidak dapat mengomentari kecepatan, tetapi satu liner.

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

menciptakan output

\ t \ t \ t \ t \ t

lebih disukai jika Anda tidak ingin melihat \ 0 dalam kode Anda.



1

Dalam kebanyakan kasus, Anda hanya membutuhkan string hingga panjang tertentu, katakanlah 100 spasi. Anda bisa menyiapkan larik String di mana nomor indeks sama dengan ukuran string yang diisi spasi dan mencari string, jika panjang yang dibutuhkan berada dalam batas atau membuatnya sesuai permintaan jika di luar batas.



0

Cukup ganti StringBuffer Anda dengan StringBuilder . Sulit untuk mengalahkannya.

Jika panjang Anda adalah jumlah yang besar, Anda dapat menerapkan beberapa penambahan sendiri yang lebih efisien (tapi lebih canggung), menduplikasi panjangnya di setiap iterasi:

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

Anda juga dapat mencoba Arrays.fill()pendekatan tersebut ( FrustratedWithFormsDesigner jawaban).


Bisakah Anda menyebutkan beberapa variabel lebih dari satu karakter?
C. Ross

0

Anda bisa menggantinya StringBufferdenganStringBuilder (yang terakhir tidak disinkronkan, mungkin lebih cepat dalam satu aplikasi utas)

Dan Anda dapat membuat StringBuilderinstance satu kali, alih-alih membuatnya setiap kali Anda membutuhkannya.

Sesuatu seperti ini:

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

  }

Dan gunakan seperti ini:

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

Jika Anda menganggap createAvariabel Anda sebagai instance, Anda dapat menghemat waktu membuat instance.

Ini bukan utas aman, jika Anda memiliki banyak utas, setiap utas harus memiliki salinannya sendiri.


0

Untuk kinerja yang baik, gabungkan jawaban dari aznilamir dan dari FrustratedWithFormsDesigner

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

Sesuaikan ukuran BLANKStergantung pada kebutuhan Anda. BLANKSString spesifik saya sekitar 200 karakter.


0

Punya metode seperti ini. Ini menambahkan ruang yang dibutuhkan pada akhir yang diberikan Stringuntuk memberikan Stringpanjang tertentu.

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

Ingin String memiliki ukuran tetap, sehingga Anda dapat membalut atau memotong, untuk mentabulasi data ...

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|

Referensi yang sangat baik di sini .


0

Ini berhasil bagi saya tanpa menggunakan perpustakaan eksternal di Java 8

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

Dan hasilnya

testtesttest

0

int c = 10; String spasi = String.format ("%" + c + "c", ''); ini akan menyelesaikan masalah Anda.


-1

Metode sederhana seperti di bawah ini juga dapat digunakan

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

Ini jauh lebih lambat.
Slaks

Anda dapat menggunakan StringBuffer sebagai ganti rangkaian string, jika string yang Anda hadapi berukuran besar. Itu akan sangat mempengaruhi kecepatan
Yashpal Singla

-2

bagaimana dengan ini?

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

EDIT: Saya sudah menulis kode sederhana untuk menguji konsep dan di sini apa yang saya temukan.

Metode 1: menambahkan ruang tunggal dalam satu lingkaran:

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

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

    return sb.toString();
  }

Metode 2: tambahkan 100 spasi dan loop, lalu substring:

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

Hasilnya saya dapat membuat 12.345.678 spasi:

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

dan untuk 10.000.000 ruang:

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

menggabungkan alokasi langsung dan iterasi selalu membutuhkan waktu lebih sedikit, rata-rata 60 ms lebih sedikit ketika membuat ruang besar. Untuk ukuran yang lebih kecil, kedua hasilnya dapat diabaikan.

Tapi tolong terus berkomentar :-)


3
@ aznilamir: Hm, apa yang akan Anda lakukan untuk ruang 10k?
Jayan

Idenya adalah untuk menggabungkan lingkaran dan alokasi langsung 100 ruang. Berikut ini cuplikan kode:
aznilamir

Mengapa Anda menggunakan beberapa penambahan untuk menambah 100 karakter? Mengapa tidak menambahkan 100 char?
nycynik

-3

Saya tahu tidak ada metode bawaan untuk apa yang Anda tanyakan. Namun, untuk panjang tetap kecil seperti 10, metode Anda harus cepat.


Kalau saja itu panjang tetap kecil seperti 10.
C. Ross
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.