Substring'i Alın - belirli bir karakterden önceki her şey


124

Her şeyi bir dizedeki - karakterinden önce almanın en iyi yolunu bulmaya çalışıyorum. Bazı örnek dizeler aşağıdadır. Önceki dizenin uzunluğu - değişebilir ve herhangi bir uzunlukta olabilir

223232-1.jpg
443-2.jpg
34443553-5.jpg

bu yüzden 0 başlangıç ​​dizininden hemen öncesine kadar olan değere ihtiyacım var -. Böylece alt dizeler 223232, 443 ve 34443553 olur.

Yanıtlar:


144

.Net Fiddle örneği

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("223232-1.jpg".GetUntilOrEmpty());
        Console.WriteLine("443-2.jpg".GetUntilOrEmpty());
        Console.WriteLine("34443553-5.jpg".GetUntilOrEmpty());

        Console.ReadKey();
    }
}

static class Helper
{
    public static string GetUntilOrEmpty(this string text, string stopAt = "-")
    {
        if (!String.IsNullOrWhiteSpace(text))
        {
            int charLocation = text.IndexOf(stopAt, StringComparison.Ordinal);

            if (charLocation > 0)
            {
                return text.Substring(0, charLocation);
            }
        }

        return String.Empty;
    }
}

Sonuçlar:

223232
443
34443553
344

34

2
Lütfen onlara bir iyilik yapın ve bundan bir işlev yapmayı planladığını varsayarak hata kontrolü ekleyin :)
Josh

Teşekkürler Buna yakındım, ancak bu combo dışında birinin bunu yapmanın farklı bir yolu olup olmadığını merak ediyordum. Ama evet, bu harika çalışıyor ve hala oldukça kısa.
PositiveGuy

14
Doğru "bulunamadı" kontrolünü kaybetmeden tek string result = source.Substring(0, Math.Max(source.IndexOf('-'), 0))
satırlık bir lastik

2
Bunun yerine , dizginin uzunluğunun kesinlikle aştığı (burada olduğu gibi) bilindiğinde s.Substring(0, n)kullanılabilir . s.Remove(n)sn
Jeppe Stig Nielsen

@LukeH IndexOf, örneğinizde -1 döndürürse, boş bir dize döndürülür, değil mi?
ezmek

124

Bölme işlevini kullanın .

static void Main(string[] args)
{
    string s = "223232-1.jpg";
    Console.WriteLine(s.Split('-')[0]);
    s = "443-2.jpg";
    Console.WriteLine(s.Split('-')[0]);
    s = "34443553-5.jpg";
    Console.WriteLine(s.Split('-')[0]);

Console.ReadKey();
}

Eğer dizginizde bir tane yoksa -, tüm dizeyi alırsınız.


4
Birden fazla kısa çizginiz varsa, dizinizde birden çok öğe elde edersiniz.
James Dunne

2
Nitekim James, bu sadece tek bir tire bekliyorsanız bir çözüm olabilir. Sanırım istediğinizi elde etmek için atlama ve toplama gibi Linq yöntemlerini kullanabilirsiniz, ancak o zaman zaten önerilen yöntemlerden daha fazla koda sahip olursunuz. Her şey, gelen veriler hakkında ne kadar bilgi sahibi olduğunuza bağlıdır.
Dominic Cronin

7
Ve birkaç yıl sonra, James'in fikrini kabul etmekte oldukça hızlı olduğumu yeni fark ettim. Soru, dizenin belirli bir karakterden önce nasıl bulunacağını sorar. Bu karakterin diğer örnekleri bu nedenle önemsizdir ve [0] almak "sadece işe yarar" olur. Elbette bu yine de gelen verilere ne kadar güvendiğimize bağlı. Ya hiç '-' yoksa?
Dominic Cronin

1
Sanırım @JamesDunne, bir diziye bölünerek, bir sürü gereksiz dizge - gereksiz çöpler yaratıyorsunuz.
ezmek

1
"Gereksiz çöp" konusunda endişelenmem. Bu şekilde yaratılan herhangi bir ekstra dizgeye hemen erişilemez ve bu nedenle 0 neslinde toplanır, ki bu gerçekten son derece düşük bir ek yüktür. Çöp toplayıcı tasarımı açıkça çok sayıda kısa ömürlü öğenin neredeyse hiçbir masraf olmadan kullanılmasına izin vermek için tasarlanmıştır.
Dominic Cronin

65
String str = "223232-1.jpg"
int index = str.IndexOf('-');
if(index > 0) {
    return str.Substring(0, index)
}

olumlu oy, çünkü ayırıcının dizinini bilmem gerekiyor
Piero Alberto

3
Bu aslında Fredou'nun verdiği yanıtın aynısıdır (şu anda en iyi yanıt), tek fark, hiçbir eşleşme bulunmayan durumu ele almamasını sağlar.
Dominic Cronin

7

Bu konu başladığından beri işler biraz ilerledi.

Şimdi kullanabilirsin

string.Concat(s.TakeWhile((c) => c != '-'));

Bu, performans açısından bariz IndexOf ve Substring kombinasyonunu nasıl karşılaştırır? Her karakteri bir StringBuilder'a eklediğini ve ardından sonunda bir dize ürettiğini varsayıyorum. Ayrıca, karıştırılmış birkaç işlev çağrısı da var. Substring, -1'i "dizenin sonu" anlamına gelen "uzunluk" bağımsız değişkeni olarak alabilseydi iyi olurdu.
ezmek

1
Verimlilik için daha kötü. Dediğiniz gibi, bir dize oluşturucu kullanıyor ve kodu inceledikten sonra, her karakter için ToString'i çağırıyor gibi görünüyor. Birden fazla karakter arıyorsanız, lambdayı kolayca yeniden yazabileceğiniz için daha açıktır.
Anthony Wieser

5

Bunu yapmanın bir yolu şunlarla String.Substringbirlikte kullanmaktır String.IndexOf:

int index = str.IndexOf('-');
string sub;
if (index >= 0)
{
    sub = str.Substring(0, index);
}
else
{
    sub = ... // handle strings without the dash
}

0 konumundan başlayarak, tüm metni kısa çizgiye kadar olan ancak dahil etmeden döndürün.


indeks <= 0 ise sadece string.empty döndürmelisiniz.
İade Yok İade Yok

5
@NRNR: Öyle diyorsan. OP iş gereksinimlerini bilir, siz veya ben değil.
Michael Petrotta

0

BrainCore'un cevabına dayanarak:

    int index = 0;   
    str = "223232-1.jpg";

    //Assuming we trust str isn't null 
    if (str.Contains('-') == "true")
    {
      int index = str.IndexOf('-');
    }

    if(index > 0) {
        return str.Substring(0, index);
    }
    else {
       return str;
    }

0

Bu amaçla normal ifadeler kullanabilirsiniz, ancak girdi dizesi normal ifadeye karşı uyuşmadığında ekstra istisnalardan kaçınmak iyidir.

İlk olarak, normal ifade kalıbına kaçmanın ekstra baş ağrısından kaçınmak için - sadece bu amaç için işlevi kullanabiliriz:

String reStrEnding = Regex.Escape("-");

Bunun hiçbir şey yapmadığını biliyorum - "-" ile aynı Regex.Escape("=") == "="şeydir, ancak örneğin karakterin olması durumunda fark yaratacaktır @"\".

O zaman dizenin başından dizge sonuna kadar eşleşmemiz gerekir veya alternatif olarak eğer son bulunmazsa - hiçbir şeyle eşleşmez. (Boş dize)

Regex re = new Regex("^(.*?)" + reStrEnding);

Uygulamanız performans açısından kritikse - o zaman yeni Regex için ayrı bir satır, değilse - her şeyi tek satırda alabilirsiniz.

Ve son olarak dizeyle eşleştirin ve eşleşen kalıbı çıkarın:

String matched = re.Match(str).Groups[1].ToString();

Bundan sonra, başka bir cevapta yapıldığı gibi ayrı bir fonksiyon yazabilir veya satır içi lambda fonksiyonu yazabilirsiniz. Şimdi her iki gösterimi de kullanarak yazdım - satır içi lambda işlevi (varsayılan parametreye izin vermez) veya ayrı işlev çağrısı.

using System;
using System.Text.RegularExpressions;

static class Helper
{
    public static string GetUntilOrEmpty(this string text, string stopAt = "-")
    {
        return new Regex("^(.*?)" + Regex.Escape(stopAt)).Match(text).Groups[1].Value;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Regex re = new Regex("^(.*?)-");
        Func<String, String> untilSlash = (s) => { return re.Match(s).Groups[1].ToString(); };

        Console.WriteLine(untilSlash("223232-1.jpg"));
        Console.WriteLine(untilSlash("443-2.jpg"));
        Console.WriteLine(untilSlash("34443553-5.jpg"));
        Console.WriteLine(untilSlash("noEnding(will result in empty string)"));
        Console.WriteLine(untilSlash(""));
        // Throws exception: Console.WriteLine(untilSlash(null));

        Console.WriteLine("443-2.jpg".GetUntilOrEmpty());
    }
}

Btw - düzenli ifade kalıbını olarak değiştirmek, kalıp "^(.*?)(-|$)"bulunana kadar "-"veya kalıp bulunamazsa, dizenin sonuna kadar her şeyi toplayın.


0

LINQy yolu

String.Concat ("223232-1.jpg" .TakeWhile (c => c! = '-'))

(Ancak, boş değeri test etmeniz gerekir;)

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.