简体   繁体   中英

Build the string dynamically based on the length in c#

My aim is to generate a string . which has following conditions.

First i will take an empty string and start building the string based on length.

Example:

I have an empty string "" .

In the first step i want to add a string till 8 characters, means first my string is "" then till 8 characters my string should contain the value Hiwor so finally my string will be Hiwor if there is no value empty value should be padded in the string .

In the second step i want to add the string meena till 10 positions , so my final string should be Hiwor meena . In this way i want to build my string. Ho can i achieve this. Can you please help me.

Sample: initial string ""

first step adding string Hiwor till 8 positions ,

so final string should be Hiwor

second step adding string meena till 10 postions

so final string should be Hiwor meena .

Till now i tried like this

 Dictionary<string, Int16> transLine = new Dictionary<string, Int16>();

            transLine.Add("ProductCode", 1);

            transLine.Add("ApplicantFirstName", 12);

            transLine.Add("ApplicantMiddleInitial", 1);

            transLine.Add("partner", 1);

            transLine.Add("employee", 8);

            List<string> list = new List<string>();
            list.Add("grouplife");
            list.Add("meena");
            list.Add("d");
            list.Add("yes");
            list.Add("yes");

            StringBuilder sb = new StringBuilder();
            foreach (var listItem in list)
            {
                foreach (var item in transLine)
                {
                    if (listItem == item.Key)
                    {
                        var length = item.Value;
                        sb.Insert(length, item.Key);
                    }
                }
            }

but it is throwing me an exception. Index was out of range. Must be non-negative and less than the size of the collection.

Firstly define an extension method for StringBuilder:

public static class StringBuilderExtensions
{
    public static void AppendPadded(this StringBuilder builder, string value, int length);
    {
        builder.Append($"{value}{new string(' ', length)}".Substring(0, length));
    }
    public static void AppendPadded(this StringBuilder builder, int value, int length);
    {
        builder.Append($"{new string('0', length)}{value}".Reverse().ToString().Substring(0, length).Reverse().ToString());
    }
}

Then use:

StringBuilder builder = new StringBuilder();
builder.AppendPadded("Hiwor", 8);
builder.AppendPadded("meena", 10);
return builder.ToString();

Or with your example:

foreach (string item in list)
    builder.AppendPadded(item, transLine[item]);

EDIT: Ok, so looks like you want to be able to define a format then build the string using it. Try:

(you will need to reference System.ComponentModel.DataAnnotations and System.Reflection for this)

public abstract class AnItem
{
    private static int GetLength(PropertyInfo property)
    {
        StringLengthAttribute attribute = property.GetCustomAttributes(typeof(StringLengthAttribute), true).FirstOrDefault() as StringLengthAttribute;
        if (attribute == null)
            throw new Exception($"StringLength not specified for {property.Name}");
        return attribute.MaxLength();
    }
    private string GetPropertyValue(PropertyInfo property)
    {
        if (property.PropertyType == typeof(string))
            return property.GetValue(this);
        else if (property.PropertyType == typeof(int))
            return property.GetValue(this).ToString();
        else
            throw new Exception($"Property '{property.Name}' is not a supported type");
    }
    private static void SetPropertyValue(object item, PropertyInfo property, string value)
    {
        if (property.PropertyType == typeof(string))
            property.SetValue(item, value, null);
        else if (property.PropertyType == typeof(int))
            property.SetValue(item, int.Parse(value), null);
        else
            throw new Exception($"Property '{property.Name}' is not a supported type");
    }
    public string GetPaddedString()
    {
        StringBuilder builder = new StringBuilder();
        PropertyInfo[] properties = GetType().GetProperties();
        foreach (PropertyInfo property in properties)
            builder.AppendPadded(GetPropertyValue(property), GetLength(property));
        return builder.ToString();
    }
    public static T CreateFromPaddedString<T>(string paddedString) where T : AnItem, new()
    {
        T item = new T();
        int offset = 0;
        PropertyInfo[] properties = typeof(T).GetProperties();
        foreach (PropertyInfo property in properties)
        {
            int length = GetLength(property);
            if (offset + length > paddedString.Length)
                throw new Exception("The string is too short");
            SetPropertyValue(item, property, paddedString.Substring(offset, length)));
            offset += length;
        }
        if (offset < paddedString.Length)
            throw new Exception("The string is too long");
        return item;
    }
}
public class MyItem : AnItem
{
    [StringLength(1)]
    public string ProductCode { get; set; }

    [StringLength(12)]
    public string ApplicantFirstName { get; set; }

    [StringLength(1)]
    public string ApplicantMiddleInitial { get; set; }

    [StringLength(1)]
    public string Partner { get; set; }

    [StringLength(8)]
    public string Employee { get; set; }
}

Then use it:

MyItem item = new MyItem
{
    ProductCode = "grouplife",
    ApplicantFirstName = "meena",
    ApplicantMiddleInitial = "d",
    Partner = "yes",
    Employee = "yes"
};

string paddedString = item.GetPaddedString();

And to read a string to get an item:

MyItem item = AnItem.CreateFromPaddedString<MyItem>(paddedString);

At first I want to say something more about your exception:

Index was out of range. Must be non-negative and less than the size of the collection.

As the exception already said. The problem is that you want to access a position within your new StringBuilder sb which does not exists.

StringBuilder sb = new StringBuilder();

After this line your new sb is empty. There is no single character in it. So you can only access the index at position 0 . But almost in your first iteration of the inner for-each loop you want to target the index 1 and try to insert your string at the position 1 , which does not exists.

// length: 1 and item.Key: ProductCode
sb.Insert(length, item.Key); 

So how to solve this. You can use a feature from String.Format() or since C#6 the string interpolation.

So for example:

String.Format()

var sb = new StringBuilder(string.Empty);      // sb: []
sb.Append(string.Format("{0, -8}", "Hiwor"));  // sb: [Hiwor   ]
sb.Append(string.Format("{0,-10}", "meena"));  // sb: [Hiwor   meena     ]

C#6 String Interpolation

var sb = new StringBuilder(string.Empty);  // sb: []
sb.Append($"{"Hiwor", -8}");               // sb: [Hiwor   ]
sb.Append($"{"meena", -10}");              // sb: [Hiwor   meena     ]

// ...

Targeting your edit:

With your given list items you will never get a match with any of your dictionary keys.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM