строка разделена на индекс / параметры? - PullRequest
8 голосов
/ 22 августа 2011

Непосредственно перед тем, как написать свою собственную функцию, я просто хотел проверить, существует ли такая функция, как string.split(string input, params int[] indexes) в библиотеке .NET?Эта функция должна разбивать строку по индексам, которые я передаю ей.

Редактировать: я не должен был добавлять предложение string.join - это сбивало с толку.

Ответы [ 8 ]

13 голосов
/ 22 августа 2011

Вы можете использовать String метод экземпляра Подстрока .

string a = input.Substring(0, 10);
string b = input.Substring(10, 5);
string c = input.Substring(15, 3);
5 голосов
/ 05 ноября 2015

Все остальные ответы казались слишком сложными, поэтому я сделал удар.

using System.Linq;

public static class StringExtensions
{
    /// <summary>
    ///     Returns a string array that contains the substrings in this instance that are delimited by specified indexes.
    /// </summary>
    /// <param name="source">The original string.</param>
    /// <param name="index">An index that delimits the substrings in this string.</param>
    /// <returns>An array whose elements contain the substrings in this instance that are delimited by one or more indexes.</returns>
    /// <exception cref="ArgumentNullException"><paramref name="index" /> is null.</exception>
    /// <exception cref="ArgumentOutOfRangeException">An <paramref name="index" /> is less than zero or greater than the length of this instance.</exception>
    public static string[] SplitAt(this string source, params int[] index)
    {
        index = index.Distinct().OrderBy(x => x).ToArray();
        string[] output = new string[index.Length + 1];
        int pos = 0;

        for (int i = 0; i < index.Length; pos = index[i++])
            output[i] = source.Substring(pos, index[i] - pos);

        output[index.Length] = source.Substring(pos);
        return output;
    }
}
2 голосов
/ 22 августа 2011

Метод Split делит строку на основе шаблона распознавания.Идеально подходит для разбиения списков через запятую и т. Д.

Но вы правы, нет встроенных строковых методов для достижения того, что вы хотите.

1 голос
/ 09 марта 2015

Одно из возможных решений:

public static class StringExtension
{
    public static string[] Split(this string source, params int[] sizes)
    {
        var length = sizes.Sum();
        if (length > source.Length) return null;

        var resultSize = sizes.Length;
        if (length < source.Length) resultSize++;

        var result = new string[resultSize];

        var start = 0;
        for (var i = 0; i < resultSize; i++)
        {
            if (i + 1 == resultSize)
            {
                result[i] = source.Substring(start);
                break;
            }

            result[i] = source.Substring(start, sizes[i]);
            start += sizes[i];
        }

        return result;
    }
}
0 голосов
/ 05 июня 2019

Версия с "List " в качестве возврата.

Вызывающий

string iTextLine = "02121AAAARobert Louis StevensonXXXX"
int[] tempListIndex = new int[] {
    // 0 -  // 0number  (exclude first)
    5,      // 1user
    9,      // 2name
    31      // role
};  

// GET - words from indexes
List<string> tempWords = getListWordsFromLine(iTextLine, tempListIndex);

method

/// <summary>
/// GET - split line in parts using index cuts
/// </summary>
/// <param name="iListIndex">Input List of indexes</param>
/// <param name="iTextLine">Input line to split</param>
public static List<string> getListWordsFromLine(string iTextLine, int[] iListIndex)
{
    // INIT
    List<string> retObj = new List<string>(); 
    int currStartPos = 0;
    // GET - clear index list from dupl. and sort it
    int[] tempListIndex = iListIndex.Distinct()
                                    .OrderBy(o => o)
                                    .ToArray();
    // CTRL
    if (tempListIndex.Length != iListIndex.Length)
    {
        // ERR
        throw new Exception("Input  iListIndex contains duplicate indexes");
    }


    for (int jj = 0; jj < tempListIndex.Length; ++jj)
    {
        try
        {
            // SET - line chunk
            retObj.Add(iTextLine.Substring(currStartPos,
                                           tempListIndex[jj] - currStartPos));
        }
        catch (Exception)
        {
            // SET - line is shorter than expected
            retObj.Add(string.Empty);                    
        }                
        // GET - update start position
        currStartPos = tempListIndex[jj];
    }
    // SET
    retObj.Add(iTextLine.Substring(currStartPos));  
    // RET
    return retObj;
}
0 голосов
/ 16 января 2019
public static IEnumerable<string> SplitAt(this string source, params int[] index)
{
    var indices = new[] { 0 }.Union(index).Union(new[] { source.Length });

    return indices
                .Zip(indices.Skip(1), (a, b) => (a, b))
                .Select(_ => source.Substring(_.a, _.b - _.a));
}

var s = "abcd";

s.SplitAt(); // "abcd"
s.SplitAt(0); // "abcd"
s.SplitAt(1); // "a", "bcd"
s.SplitAt(2); // "ab", "cd"
s.SplitAt(1, 2) // "a", "b", "cd"
s.SplitAt(3); // "abc", "d"
0 голосов
/ 05 июля 2018

Это не дает прямого ответа на ваш обобщенный вопрос, но в наиболее вероятном случае (или, по крайней мере, в случае, когда я искал ответ, когда натолкнулся на этот вопрос SO) где indexes является единственным int, этот метод расширения немного чище, чем возвращение массива string[], особенно в C # 7.

Что бы это ни стоило, я протестировал использование string.Substring() против создания двух char[] массивов, вызова text.CopyTo() и возврата двух строк путем вызова new string(charArray). Использование string.Substring() было примерно в два раза быстрее.

C # 7 синтаксис

пример jdoodle.com

public static class StringExtensions
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static (string left, string right) SplitAt(this string text, int index) => 
        (text.Substring(0, index), text.Substring(index));
}

public static class Program
{
    public static void Main()
    {
        var (left, right) = "leftright".SplitAt(4);
        Console.WriteLine(left);
        Console.WriteLine(right);
    }
}

C # 6 синтаксис

jdoodle.com пример

Примечание. Использование Tuple<string, string> в версиях, предшествующих C # 7, не сильно экономит многословие, и на самом деле может быть чище просто возвращать массив string[2].

public static class StringExtensions
{
    // I'd use one or the other of these methods, and whichever one you choose, 
    // rename it to SplitAt()

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Tuple<string, string> TupleSplitAt(this string text, int index) => 
        Tuple.Create<string, string>(text.Substring(0, index), text.Substring(index));

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static string[] ArraySplitAt(this string text, int index) => 
        new string[] { text.Substring(0, index), text.Substring(index) };
}

public static class Program
{
    public static void Main()
    {
        Tuple<string, string> stringsTuple = "leftright".TupleSplitAt(4);
        Console.WriteLine("Tuple method");
        Console.WriteLine(stringsTuple.Item1);
        Console.WriteLine(stringsTuple.Item2);

        Console.WriteLine();

        Console.WriteLine("Array method");
        string[] stringsArray = "leftright".ArraySplitAt(4);
        Console.WriteLine(stringsArray[0]);
        Console.WriteLine(stringsArray[1]);
    }
}
0 голосов
/ 22 августа 2011

Всегда есть регулярные выражения.

Вот пример, из которого можно расширить:

 string text = "0123456789ABCDEF";
 Match m = new Regex("(.{7})(.{4})(.{5})").Match(text);
 if (m.Success)
 {
     var result = new string[m.Groups.Count - 1];
     for (var i = 1; i < m.Groups.Count; i++)
         result[i - 1] = m.Groups[i].Value;
 }

Вот функция, которая инкапсулирует вышеуказанную логику:

    public static string[] SplitAt(this string text, params int[] indexes)
    {
        var pattern = new StringBuilder();
        var lastIndex = 0;
        foreach (var index in indexes)
        {
            pattern.AppendFormat("(.{{{0}}})", index - lastIndex);
            lastIndex = index;
        }
        pattern.Append("(.+)");

        var match = new Regex(pattern.ToString()).Match(text);
        if (! match.Success)
        {
            throw new ArgumentException("text cannot be split by given indexes");
        }

        var result = new string[match.Groups.Count - 1];
        for (var i = 1; i < match.Groups.Count; i++)
            result[i - 1] = match.Groups[i].Value;
        return result;            
    }

Это было написано довольно быстро, но я считаю, что это иллюстрирует мои моменты и подчеркивает мои замечания автору комментария, Михаил.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...