Stringbuilder ile oluşturulmuş bir dizeden son karakteri kaldırmanın en iyi yolu


92

Şunlara sahibim

data.AppendFormat("{0},",dataToAppend);

Bununla ilgili sorun, onu bir döngüde kullanıyorum ve deneme amaçlı bir virgül olacak. Sondaki virgülü kaldırmanın en iyi yolu nedir?

Veriyi bir dizgenin alt dizesine dönüştürmem gerekir mi?


10
string.Join(",", yourCollection)? Düzenleme: cevap olarak eklendi.
Vlad


@Chris: Bu şekilde bir StringBuilder'a ihtiyacınız yok.
Vlad

belki daha sonra kaldırmak yerine virgül eklemekten kaçınabilirsiniz. Bakınız: stackoverflow.com/questions/581448/… (Jon Skeet'in cevabı)
Paolo Falabella

@Vlad Evet üzgünüm, bunu yanlış anladım; Onu, döngüsünün tamamen yerine geçecek bir şey olarak değil, son inşa edilmiş ipi değiştirmek için bir öneri olarak sunduğunuzu sanıyordum. (Yorumumu zamanında sildiğimi sanıyordum, sanmıyorum!)
Chris Sinclair

Yanıtlar:


224

En basit ve en etkili yol bu komutu gerçekleştirmektir:

data.Length--;

bunu yaparak işaretçiyi (yani son indeks) bir karakter geri hareket ettirirsiniz, ancak nesnenin değişkenliğini değiştirmezsiniz. Aslında, a'yı temizlemek StringBuilderde en iyi şekilde yapılır Length(ancak Clear()bunun yerine yöntemi netlik için kullanın, çünkü uygulaması böyle görünüyor):

data.Length = 0;

yine, çünkü ayırma tablosunu değiştirmez. Bunu artık bu baytları tanımak istemiyorum demek gibi düşünün. Şimdi, aradığında bile ToString(), geçmişindeki hiçbir şeyi tanımaz Length, pekala, yapamaz. Sağladığınızdan daha fazla alan ayıran değiştirilebilir bir nesnedir, basitçe bu şekilde inşa edilmiştir.


2
re data.Length = 0;: tam olarak ne StringBuilder.Clearyapar, bu nedenle StringBuilder.Clearniyetin netliği için kullanılması tercih edilir .
Eren Ersönmez

@ ErenErsönmez, yeterince adaletli dostum, ne işe yaradığını daha net ifade etmeliydim Clear()ama komik bir şey. Budur ilk satırı ait Clear()yönteme. Ancak, arayüzün aslında o zaman a return this;. Şimdi beni öldüren şey bu. Ayar Length = 0zaten sahip referans değişir, neden kendinizi dönmek?
Mike Perrenoud

12
"Akıcı" bir şekilde kullanabilmek için olduğunu düşünüyorum. Appendkendini de döndürür.
Eren Ersönmez

43

Sadece kullan

string.Join(",", yourCollection)

Bu şekilde StringBuilderve döngüsüne ihtiyacınız olmaz .




Asenkron durum hakkında uzun bir ekleme. 2019 itibariyle, verilerin eşzamansız olarak gelmesi nadir görülen bir kurulum değildir.

Verilerinizin eşzamansız koleksiyonda olması durumunda string.Joinaşırı yük alma yoktur IAsyncEnumerable<T>. Ancak kodustring.Join el ile oluşturmak kolaydır :

public static class StringEx
{
    public static async Task<string> JoinAsync<T>(string separator, IAsyncEnumerable<T> seq)
    {
        if (seq == null)
            throw new ArgumentNullException(nameof(seq));

        await using (var en = seq.GetAsyncEnumerator())
        {
            if (!await en.MoveNextAsync())
                return string.Empty;

            string firstString = en.Current?.ToString();

            if (!await en.MoveNextAsync())
                return firstString ?? string.Empty;

            // Null separator and values are handled by the StringBuilder
            var sb = new StringBuilder(256);
            sb.Append(firstString);

            do
            {
                var currentValue = en.Current;
                sb.Append(separator);
                if (currentValue != null)
                    sb.Append(currentValue);
            }
            while (await en.MoveNextAsync());
            return sb.ToString();
        }
    }
}

Veriler eşzamansız olarak geliyorsa ancak arayüz IAsyncEnumerable<T>desteklenmiyorsa (yorumlarda bahsedildiği gibi SqlDataReader), verileri bir şuna sarmak nispeten kolaydır IAsyncEnumerable<T>:

async IAsyncEnumerable<(object first, object second, object product)> ExtractData(
        SqlDataReader reader)
{
    while (await reader.ReadAsync())
        yield return (reader[0], reader[1], reader[2]);
}

ve kullan:

Task<string> Stringify(SqlDataReader reader) =>
    StringEx.JoinAsync(
        ", ",
        ExtractData(reader).Select(x => $"{x.first} * {x.second} = {x.product}"));

Kullanım için Select, sen Nuget paketi kullanmak gerekir System.Interactive.Async. Burada derlenebilir bir örnek bulabilirsiniz.


12
En iyi cevap, sorunu çözen değil, onu engelleyendir.
LastTribunal

1
@Seabizkit: Tabii ki! Bu arada, tüm soru C # ile ilgili.
Vlad

1
@ Memnun oldum, ham test gibi basit bir test yaptığım için sadece iki kez kontrol ettim ve aynı şeyi üretmediler. string.Join(",", yourCollection)hala ,sonunda bir var. bu nedenle yukarıdaki ie string.Join(",", yourCollection)verimsizdir ve kendi başına ortadan kaldırmaz.
Seabizkit

2
@Seabizkit: Çok tuhaf! Bir örnek gönderebilir misin? Kodumda
Vlad

2
Yıllarca bir dize oluşturucu oluşturmak için bir döngü kullanıyorum ve ardından sondaki virgülü kaldırın ve bunu kullanabilirdim. Bahşiş için teşekkürler!
Caverman

11

Döngüden sonra aşağıdakileri kullanın.

.TrimEnd(',')

veya basitçe değiştir

string commaSeparatedList = input.Aggregate((a, x) => a + ", " + x)

4
StringBuilder'ı string değil kullanıyor. Üstelik oldukça etkisizdir: önce sicime dönüştürme sonra kırpma.
Piotr Stapp

veyastring.Join(",", input)
Tvde1

11

Buna ne dersin..

string str = "The quick brown fox jumps over the lazy dog,";
StringBuilder sb = new StringBuilder(str);
sb.Remove(str.Length - 1, 1);

7

Stringbuilder'ın uzunluğunu değiştirmeyi tercih ederim:

data.Length = data.Length - 1;

4
Neden basitçe data.Length--ya da değil --data.Length?
Kodlama gitti

Genellikle data.Length kullanırım - ancak bir durumda kaldırmak istediğim karakterden sonraki boş bir değer nedeniyle 2 karakter geri gitmek zorunda kaldım. Trim bu durumda da işe yaramadı bu yüzden data.Length = data.Length - 2; çalıştı.
Caverman

Trim, bir dizenin yeni bir örneğini döndürür, stringbuilder nesnesinin içeriğini değiştirmez
bastos.sergio

@GoneCoding Visual Basic .NET desteklemiyor --ya ++ da kullanabilirsiniz data.Length -= 1, yoksa bu cevap da işe yarayacaktır.
Jason S

3

Döngü algoritmanızı değiştirmenizi tavsiye ederim:

  • Virgülü öğeden SONRA değil, ÖNCE ekleyin
  • False ile başlayan bir boolean değişkeni kullanın, ilk virgülü gizleyin
  • Bu boole değişkenini test ettikten sonra true olarak ayarlayın

2
Bu, muhtemelen tüm öneriler arasında en az verimli olanıdır (ve daha fazla kod gerektirir).
Kodlama gitti

1
Bak @Vlad answer
Noctis

3

Bir string.Joinöğe koleksiyonunu virgülle ayrılmış dizeye dönüştürmek için yöntemi kullanmalısınız . Başta veya sonda virgül olmamasını sağlayacak ve dizenin verimli bir şekilde (gereksiz ara dizeler olmadan) oluşturulmasını sağlayacaktır.


2

Evet, döngü tamamlandıktan sonra onu bir dizeye dönüştürün:

String str = data.ToString().TrimEnd(',');

3
oldukça etkisizdir: önce dizeye dönüştürme, sonra kırpma.
Piotr Stapp

2
@Garath "Verimsiz" demek istediyseniz, katılmıyorum. Ama olur etkili.
DonBoitnott

2

İki seçeneğiniz var. Birincisi çok kolay kullanım Removeyöntemi oldukça etkilidir. İkinci yol, ToStringbaşlangıç ​​dizini ve bitiş dizini ile kullanmaktır ( MSDN belgeleri )



1

En basit yol Join () yöntemini kullanmaktır:

public static void Trail()
{
    var list = new List<string> { "lala", "lulu", "lele" };
    var data = string.Join(",", list);
}

StringBuilder'a gerçekten ihtiyacınız varsa, döngüden sonra bitiş virgülünü kırpın:

data.ToString().TrimEnd(',');

4
data.ToString().TrimEnd(',');verimsiz
bastos.sergio

1
Ayrıca, "," ile biten birden çok satıra sahip olabileceğinden, StringBuilder nesnesini String'e dönüştürmek istemeyebilirsiniz
Fandango68

0

Anladım!!

AppendLineAşağıdaki gibi kullanırsanız, bu konudaki cevapların çoğu işe yaramayacaktır :

var builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length--; // Won't work
Console.Write(builder.ToString());

builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length += -1; // Won't work
Console.Write(builder.ToString());

builder = new StringBuilder();
builder.AppendLine("One,");
Console.Write(builder.TrimEnd(',')); // Won't work

Beni Oynat

NEDEN??? @ (& ** (& @ !!

Sorun basit ama çözmem biraz zaman aldı: Çünkü sonunda 2 görünmez karakter daha var CRve LF(Carriage Return ve Line Feed). Bu nedenle, son 3 karakteri çıkarmanız gerekir:

var builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length -= 3; // This will work
Console.WriteLine(builder.ToString());

Sonuç olarak

Kullanım Length--veya Length -= 1aradığınız son yöntem ise Append. Length =- 3Aradığınız son yöntem iseniz kullanın AppendLine.

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.