Get Substring - все до определенного символа


125

Я пытаюсь найти лучший способ получить все до символа - в строке. Ниже приведены некоторые примеры строк. Длина строки перед - варьируется и может быть любой длины.

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
Пожалуйста, сделайте им одолжение и добавьте также проверку ошибок, если он планирует сделать из этого какую-то функцию :)
— Джош

Спасибо, я был близок к этому, но мне было любопытно, есть ли у кого-нибудь другой способ сделать это, кроме этой комбинации. Но да, это отлично работает и все еще довольно короткое.
— PositiveGuy

14
Если вы хотите однострочник без потери надлежащей проверки «не найдено», вы можете сделать что-то вроде этого:string result = source.Substring(0, Math.Max(source.IndexOf('-'), 0))
— LukeH,

2
Вместо s.Substring(0, n)одного можно использовать, s.Remove(n)когда известно (как здесь), что длина строки sстрого превышает n.
— Jeppe Stig Nielsen

@LukeH Если IndexOf возвращает -1 в вашем примере, тогда будет возвращена пустая строка, не так ли?
— Crush

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, такие как skip и aggregate, чтобы получить то, что вы хотели, но тогда у вас будет больше кода, чем методы, которые уже были предложены. Все зависит от того, насколько вы знаете о входящих данных.
— Доминик Кронин,

7
И через несколько лет я только что осознал, что слишком поспешил признать точку зрения Джеймса. Вопрос спрашивает, как найти строку перед определенным символом. Таким образом, дальнейшие экземпляры этого символа не имеют значения, и взятие [0] «просто сработает». Конечно, это все еще зависит от того, насколько мы доверяем входящим данным. Что, если вообще нет "-"?
— Доминик Кронин,

1
Я думаю, что точка @JamesDunne заключалась в том, что, разбиваясь на массив, вы создаете кучу ненужных строк - ненужный мусор.
— Crush

1
Я бы не стал беспокоиться о «ненужном мусоре». Любые дополнительные строки, созданные таким образом, будут немедленно недоступны и, следовательно, будут собраны в поколении 0, что действительно является чрезвычайно низкими накладными расходами. Конструкция сборщика мусора явно предназначена для использования большого количества недолговечных элементов практически без затрат.
— Доминик Кронин

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

проголосовать за, потому что мне нужно знать индекс разделителя
— Пьеро Альберто

3
Фактически это тот же ответ, что дал Фреду (в настоящее время лучший ответ), за исключением того, что в нем не учитывается случай, когда совпадение не найдено.
— Доминик Кронин

7

С момента начала этой беседы все немного изменилось.

Теперь вы можете использовать

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

Как это соотносится с производительностью очевидной комбинации IndexOf и Substring? Я предполагаю, что он добавляет каждый символ в StringBuilder, а затем создает строку в конце. Также здесь смешано несколько вызовов функций. Было бы неплохо, если бы Substring могла просто принимать -1 в качестве аргумента «длина», означающего «конец строки».
— Crush

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, вернуть весь текст до тире, но не включая его.


если index <= 0, вы должны просто вернуть string.empty.
— Возврат невозможен, возврату не подлежит

5
@NRNR: если вы так говорите. OP знает бизнес-требования, а не вы или я
— Майкл Петротта,

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! = '-'))

(Но вам нужно проверить на null;)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.