Есть ли хороший шаблон проектирования C # для разбора строк, которые при разделении имеют разные объемы данных? - PullRequest
0 голосов
/ 12 марта 2011

Я имею дело со значениями, разделенными запятыми, присланными мне в виде строки. Строки бывают разных структур (то есть разные типы данных в разных местах строки, а также различные объемы данных). Таким образом, хотя одна строка может быть представлена ​​как:

- общие данные, идентификатор, int, строка, строка, строка.

Другой может быть представлен как:

- общие данные, идентификатор, int, int, строка, строка, строка.

Цели разработки:

  • Общий метод разбора
  • Общая проверка (то есть int.TryParse () возвращает true)
  • Легко умеет добавлять различные структуры

Существует ли хороший шаблон проектирования или комбинация шаблонов проектирования, позволяющая мне анализировать значения, проверять их и возвращать объект только в том случае, если было получено правильное количество значений и эти значения были ожидаемыми типами данных?

Примечание: Я имею дело с более чем 30 различными строковыми структурами.

Ответы [ 5 ]

1 голос
/ 12 марта 2011

Если все строки начинаются с common data, identifier, а за ними следует переменная, но ожидаемый (т.е. известный на основе идентификатора) набор значений, тогда табличный подход мог бы работать хорошо. Чтобы продолжить ваш пример, скажем, у вас есть два разных типа:

  • общие данные, идентификатор, int, строка, строка, строка.
  • общие данные, идентификатор, int, int, строка, строка, строка.

Вы можете создать класс, который определяет, что вы ищете:

class ItemDesc
{
    public string Ident { get; private set; }
    public string Fields { get; private set; }
    public ItemDesc(string id, string flds)
    {
        Ident = id;
        Fields = flds;
    }
}

Свойство Fields - это просто строка, содержащая описания односимвольных типов для переменных данных. То есть "isss" будет интерпретироваться как int,string,string,string.

Затем вы можете создать Dictionary<string, ItemDesc>, который вы можете использовать для поиска:

Dictionary<string, ItemDesc> ItemLookup = new Dictionary<string, ItemDesc>
{
    { "ItemType1", new ItemDesc("ItemType1", "isss") },
    { "ItemType2", new ItemDesc("ItemType2", "iisss") },
};

Теперь, когда вы читаете строку, используйте string.Split(), чтобы разбить ее на поля. Получите идентификатор, найдите его в словаре, чтобы получить описания элементов, а затем проанализируйте остальные поля. Что-то вроде:

string line = GetLine();
var fields = line.Split(',');
// somehow get the identifier
string id = GetIdentifier();
ItemDesc desc;
if (!ItemLookup.TryGetValue(id, out desc))
{
    // unrecognized identifier
}
else
{
    int fieldNo = 3; // or whatever field is after the identifier
    foreach (var c in desc.Fields)
    {
        switch (c)
        {
            case 'i' :
               // try to parse an int and save it.
               break;
            case 's' :
               // save the string
               break;
            default:
               // error, unknown field type
               break;
         }
         ++fieldNo;
    }
}
// at this point if no errors occurred, then you have a collection
// of parsed fields that you saved.  You can now create your object.
1 голос
/ 12 марта 2011

Есть несколько способов справиться с этим.Вот простой (вывод только массива объектов):

class Template
{
    // map identifiers to templates
    static Dictionary<string, string> templates = new Dictionary<string, string>
    {
        { "type1", "isss" },
        { "type2", "iisss" },
    };

    static bool ParseItem(string input, char type, out object output)
    {
        output = null;
        switch (type)
        {
            case 'i':
                int i;
                bool valid = int.TryParse(input, out i);
                output = i;
                return valid;
            case 's':
                output = input;
                return true;
        }
        return false;
    }

    public static object[] ParseString(string input)
    {
        string[] items = input.Split(',');
        // make sure we have enough items
        if (items.Length < 2)
            return null;
        object[] output = new object[items.Length - 2];
        string identifier = items[1];
        string template;
        // make sure a valid identifier was specified
        if (!templates.TryGetValue(identifier, out template))
            return null;
        // make sure we have the right amount of data
        if (template.Length != output.Length)
            return null;
        // parse each item
        for (int i = 0; i < template.Length; i++)
            if (!ParseItem(items[i + 2], template[i], out output[i]))
                return null;
        return output;
    }
}
1 голос
/ 12 марта 2011

Просто разделите их, используя string.Split(), а затем int.Parse() или int.TryParse() каждое int значение в результирующем массиве по мере необходимости.

var myStrings = string.Split(sourceString);
int myint1 = int.Parse(myStrings[0]);
0 голосов
/ 12 марта 2011

Если вы заинтересованы в возвращении реальных объектов, а не просто массивов объектов, вы можете поместить метаданные в определения классов возвращаемых объектов.Затем, когда вы получаете тип объекта, вы ищете метаданные, чтобы выяснить, где найти их значение во входном массиве.Вот быстрый пример:

namespace Parser
{
    // create metadata attribute
    class CsvPositionAttribute : Attribute
    {
        public int Position { get; set; }
        public CsvPositionAttribute(int position)
        {
            Position = position;
        }
    }

    // define some classes that use our metadata
    public class type1
    {
        [CsvPosition(0)]
        public int int1;
        [CsvPosition(1)]
        public string str1;
        [CsvPosition(2)]
        public string str2;
        [CsvPosition(3)]
        public string str3;
    }

    public class type2
    {
        [CsvPosition(0)]
        public int int1;
        [CsvPosition(1)]
        public int int2;
        [CsvPosition(2)]
        public string str1;
        [CsvPosition(3)]
        public string str2;
        [CsvPosition(4)]
        public string str3;
    }

    public class CsvParser
    {
        public static object ParseString(string input)
        {
            string[] items = input.Split(',');
            // make sure we have enough items
            if (items.Length < 2)
                return null;
            string identifier = items[1];
            // assume that our identifiers refer to a type in our namespace
            Type type = Type.GetType("Parser." + identifier, false);
            if (type == null)
                return null;
            object output = Activator.CreateInstance(type);
            // iterate over fields in the type -- you may want to use properties
            foreach (var field in type.GetFields())
                // find the members that have our position attribute
                foreach (CsvPositionAttribute attr in
                    field.GetCustomAttributes(typeof(CsvPositionAttribute),
                                              false))
                    // if the item exists, convert it to the type of the field
                    if (attr.Position + 2 >= items.Length)
                        return null;
                    else
                        // ChangeType may throw exceptions on failure;
                        // catch them and return an error
                        try { field.SetValue(output,
                            Convert.ChangeType(items[attr.Position + 2],
                                               field.FieldType));
                        } catch { return null; }
            return output;
        }
    }
}
0 голосов
/ 12 марта 2011

потребуется немного больше информации, в зависимости от вашей проблемной области, она может полностью измениться. но следующие, кажется, первый набор шаблонов, они упорядочены по пригодности.

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