web-dev-qa-db-ja.com

インデックス/パラメータで分割された文字列?

自分の関数を書く直前に、.NETライブラリにstring.split(string input, params int[] indexes)のような関数が存在するかどうかを確認したかっただけですか?この関数は、渡したインデックスの文字列を分割する必要があります。

編集:string.join文を追加するべきではありませんでした-混乱していました。

9
maxp

Stringインスタンスメソッド Substring を使用できます。

string a = input.Substring(0, 10);
string b = input.Substring(10, 5);
string c = input.Substring(15, 3);
15
Paul Ruane

他のすべての答えは複雑すぎるように見えたので、私は刺しました。

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

Splitメソッドは、認識パターンに基づいて文字列を分割します。カンマ区切りのリストなどを分解するのに最適です。

しかし、あなたは正しいです、あなたが望むものを達成するための組み込みの文字列メソッドはありません。

2
havardhu
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"
1
Andriy Tolstoy

1つの可能な解決策:

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;
    }
}
1
Igor Sheva

これはyourの一般的な質問に直接答えることはありませんが、最も一般的なケース(または少なくとも私が探していたケース)ではこれに出くわしたときの答えSO質問)ここで、indexesは単一のintですが、この拡張メソッドは_string[]_を返すよりも少しクリーンです。配列、特にC#7で。

その価値については、2つの_char[]_配列を作成し、string.Substring()を呼び出し、text.CopyTo()を呼び出して2つの文字列を返すことに対して、new string(charArray)を使用してベンチマークを行いました。 string.Substring()の使用は約2倍高速でした。

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の例

注:C#7より前のバージョンで_Tuple<string, string>_を使用しても、冗長性はそれほど節約されません。実際には、_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
dx_over_dt

正規表現は常にあります。

これは、拡張できる例です。

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

これはかなり早く書かれましたが、それは私のポイントを説明し、コメントの著者であるマイケルへの私のポイントを強調していると思います。

0
Jack

戻り値として「List <string>」を含むバージョン。

発信者

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

方法

/// <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
Roberto Mutti