Отримати підрядку - все до певних знаків


124

Я намагаюся знайти найкращий спосіб отримати все перед символом - рядок. Деякі приклади рядків нижче. Довжина струни раніше - змінюється і може бути будь-якої довжини

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

тому мені потрібно значення, яке починається від стартового індексу 0 до прямого -. Таким чином, підрядки виявляться 223232, 443 та 34443553

Відповіді:


144

.Net Fiddle приклад

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

Результати:

223232
443
34443553
344

34

2
Будь ласка, зробіть їм послугу і додайте перевірку помилок, а також припустимо, що він планує зробити функцію з цього :)
Josh

Дякую, я був близький до цього, але мені було цікаво, якщо хтось мав інший спосіб зробити це, крім цього комбо. Але так, це чудово працює і все ще досить коротко.
PositiveGuy

14
Якщо ви хотіли однолінійку, не втрачаючи належну перевірку "не знайдено", тоді ви можете зробити щось подібне:string result = source.Substring(0, Math.Max(source.IndexOf('-'), 0))
ЛукаХ

2
Замість s.Substring(0, n)одного можна використовувати, s.Remove(n)коли відомо (як тут), що довжина струни sсуворо перевищує n.
Джеппе Стіг Нільсен

@LukeH Якщо IndexOf поверне -1 у вашому прикладі, то повернеться порожня рядок, чи не так?
розчавити

124

Використовуйте функцію розділення .

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

Якщо у вашій рядку немає, -ви отримаєте всю рядку.


4
І якщо у вас є кілька дефісів, ви отримуєте кілька елементів у своєму масиві.
Джеймс Данн

2
Дійсно, Джеймс, тож це було б рішення лише тоді, коли ти очікував би лише одного дефісу. Я припускаю, що ви можете використовувати такі методи Linq, як пропуск та агрегація, щоб отримати те, що хотіли, але тоді ви отримаєте більше коду, ніж запропоновані методи. Все залежить від того, скільки ви знаєте про вхідні дані.
Домінік Кронін

7
І через кілька років я щойно зрозумів, що я занадто швидкий, щоб визнати точку Джеймса. Питання задає питання, як знайти рядок перед певним символом. Подальші випадки цього характеру не мають ніякого значення, і прийняття [0] "просто би спрацювало". Звичайно, все ще залежить від того, наскільки ми довіряємо вхідним даним. Що робити, якщо взагалі немає "-"?
Домінік Кронін

1
Я думаю, що на тему @JamesDunne було те, що, розділившись на масив, ви створюєте купу непотрібних рядків - зайвого сміття.
розчавити

1
Я б не переймався "непотрібним сміттям". Будь-які додаткові рядки, створені таким чином, були б негайно недосяжними і тому зібрані в поколінні 0, що справді є надзвичайно низьким накладним рівнем. Конструкція сміттєзбірника явно призначена для того, щоб використовувати велику кількість недовговічних предметів практично без витрат.
Домінік Кронін

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

upvote тому, що мені потрібно знати індекс сепаратора
П'єро Альберто

3
Це насправді та сама відповідь, що і Фреду (на даний момент головна відповідь), за винятком того, що вона не дозволяє обробляти випадок, коли не знайдено відповідності.
Домінік Кронін

7

З моменту початку цього потоку речі трохи змінилися.

Тепер ви можете використовувати

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

Як це порівнює ефективність роботи з очевидною комбінацією IndexOf та Substring? Я припускаю, що додає кожен символ до StringBuilder, а потім створює рядок в кінці. Також є декілька викликів функцій, змішаних. Було б добре, якби Substring міг просто прийняти -1 як аргумент "length", що означає "кінець рядка".
розчавити

1
Це гірше для ефективності. Як ви кажете, він використовує конструктор струн і, перевіривши код, схоже, викликає ToString на кожному символі. Це зрозуміліше, якщо ви шукаєте більше одного символу, оскільки ви могли легко переписати лямбда.
Ентоні Візер

5

Один із способів зробити це - використовувати String.Substringразом із String.IndexOf:

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

Починаючи з позиції 0, поверніть увесь текст до тире, але не включаючи його.


якщо індекс <= 0, ви повинні просто повернути string.empty.
Без повернення грошей не повертається

5
@NRNR: якщо ти так кажеш. ОП знає вимоги бізнесу, не ви чи я.
Майкл Петротта

0

Спираючись на відповідь BrainCore:

    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

Ви можете використовувати регулярні вирази для цієї мети, але добре уникати зайвих винятків, коли введення рядкових невідповідностей проти регулярного вираження.

По-перше, щоб уникнути зайвих головних болів від переходу на схему регулярних виразів - ми могли просто використовувати функцію для цієї мети:

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

Я знаю, що це нічого не робить - як "-" те саме, що Regex.Escape("=") == "=", але це матиме значення, наприклад, якщо характер є @"\".

Тоді нам потрібно зіставити від прохання рядка до закінчення рядка, або по черзі, якщо закінчення не знайдено - тоді нічого не відповідати. (Порожній рядок)

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

Якщо ваша програма є критичною для продуктивності - тоді окремий рядок для нового Regex, якщо ні - ви можете мати все в одному рядку.

І, нарешті, відповідність рядку та витягуванню узгодженого шаблону:

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

Після цього ви можете або написати окрему функцію, як це було зроблено в іншій відповіді, або записати вбудовану лямбда-функцію. Я писав зараз, використовуючи обидві позначення - вбудована лямбда-функція (не дозволяє параметр за замовчуванням) або окремий виклик функції.

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 - зміна шаблону регулярних виразів "^(.*?)(-|$)"дозволить підібрати або до тих пір, поки "-"шаблон не буде знайдений - підберіть все до кінця рядка.


0

Шлях LINQy

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

(Але вам потрібно перевірити на нуль;)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.