String Destructuring — Digitteck
String Destructuring
dotnet·25 February 2018·3 min read

String Destructuring

Description

A different approach into handling strings. This case is useful when you want to alter parts of a string depending on char types — for example, numbers in a string. The principle is simple: iterate through the string and separate components into 2 lists. The PartialStringIndex class stores the partial string and the index (which is the priority used to recompose).

Goal

For example given the expression "abc123def456" you can separate the string by rule char is number — the class will provide 2 lists: {"abc", "def"} and {"123", "456"}.

Usage is:

csharp
Regex regex = new Regex("[0-9]");
StringDestructure sd = StringDestructure.By("abc123def456", (ch) => regex.Match(ch.ToString()).Success);
sd.OnConditionMet((str) => str);
sd.OnConditionNotMet((str) => str.ToUpper());
string result = sd.Recompose();
///THE RESULT WILL BE "ABC123DEF456"

Implementation

csharp
public class StringDestructure
{
    private class PartialStringIndex
    {
        public string Context;
        public int Index;
    }
    //Collection of separated elements
    List ElementsMeetCondition;
    List ElementsDoNotMeetCondition;
    //altering actions on each of them
    List<Func<string, string>> ActionsOnConditionMet;
    List<Func<string, string>> ActionsOnConditionNotMet;

    private StringDestructure(string Context, Predicate predicate)
    {
        ElementsMeetCondition = new List();
        ElementsDoNotMeetCondition = new List();
        ActionsOnConditionMet = new List<Func<string, string>>();
        ActionsOnConditionNotMet = new List<Func<string, string>>();

        StringBuilder temporary = new StringBuilder();

        bool storeToCondition = false;

        int recomposeIndex = 0;
        for(int i = 0; i < Context.Length; i++)
        {
            char ch = Context[i];
            if (i == 0)
            {
                if (predicate(ch))
                {
                    temporary.Append(ch);
                    storeToCondition = true;
                }
                else
                {
                    temporary.Append(ch);
                    storeToCondition = false;
                }
            }
            else
            {
                if (predicate(ch))
                {
                    if (storeToCondition)
                    {
                        temporary.Append(ch);
                    }
                    else
                    {
                        ElementsDoNotMeetCondition.Add(new PartialStringIndex
                        {
                            Context = temporary.ToString(),
                            Index = recomposeIndex
                        });
                        recomposeIndex++;
                        temporary.Clear();
                        temporary.Append(ch);
                    }
                    storeToCondition = true;
                }
                else //if (!predicate(ch))
                {
                    if (storeToCondition)
                    {
                        ElementsMeetCondition.Add(new PartialStringIndex
                        {
                            Context = temporary.ToString(),
                            Index = recomposeIndex
                        });
                        recomposeIndex++;
                        temporary.Clear();
                        temporary.Append(ch);
                    }
                    else
                    {
                        temporary.Append(ch);
                    }
                    storeToCondition = false;
                }
            }
            if (i == Context.Length - 1)
            {
                if (storeToCondition)
                    ElementsMeetCondition.Add(new PartialStringIndex
                    {
                        Context = temporary.ToString(),
                        Index = recomposeIndex
                    });
                else
                    ElementsDoNotMeetCondition.Add(new PartialStringIndex
                    {
                        Context = temporary.ToString(),
                        Index = recomposeIndex
                    });
            }
        }
    }

    //Initializer
    public static StringDestructure By(string Context, Predicate ListSplitCondition)
    {
        return new StringDestructure(Context, ListSplitCondition);
    }

    //Add an altering action for partial strings that meet condition
    public StringDestructure OnConditionMet(Func<string, string> func)
    {
        this.ActionsOnConditionMet.Add(func);
        return this;
    }

    //Add an altering action for partial strings that do not meet condition
    public StringDestructure OnConditionNotMet(Func<string, string> func)
    {
        this.ActionsOnConditionNotMet.Add(func);
        return this;
    }

    public string Recompose()
    {
        foreach(var item in this.ElementsMeetCondition)
        {
            string partialString = item.Context;
            foreach (var action in this.ActionsOnConditionMet)
            {
                partialString = action(partialString);
            }
            item.Context = partialString;
        }

        foreach (var item in this.ElementsDoNotMeetCondition)
        {
            string partialString = item.Context;
            foreach (var action in this.ActionsOnConditionNotMet)
            {
                partialString = action(partialString);
            }
            item.Context = partialString;
        }

        List allitems =
            this.ElementsMeetCondition.Concat(this.ElementsDoNotMeetCondition).ToList();

        Comparison comparison = (first, second) =>
        {
            return first.Index.CompareTo(second.Index);
        };

        allitems.Sort(comparison);
        return string.Concat(allitems.Select(x => x.Context));
    }
}

Tags

C#.NETPractices
digitteck

© 2026 Digitteck