C # LINQ и задача сопоставления с образцом - PullRequest
0 голосов
/ 16 мая 2018

Мне нужно решение, которое проверяет, соответствует ли содержимое строки фиксированной длины ряду правил. Если нет, мне нужно получить список Правил , который не прошел, значение Ожидаемое для каждого правила и значение Фактически , содержащееся в строке.

Это мое текущее решение:

string actual = "628IDENTREGISTER153004085616P30062010EAPFEMPA013.1";

 // Dictionary<Tuple<rule, expected>, startingPostion>
 var expected = new Dictionary<Tuple<string, string>, int>
 {
   {new Tuple<string, string>("900052", "628"), 0},
   {new Tuple<string, string>("9000250", "IDENTREGISTER1"), 3},
   {new Tuple<string, string>("900092", "53004085616"), 17},
   {new Tuple<string, string>("900004", "P"), 28}, 
   {new Tuple<string, string>("900089", "30062010"), 29},
   {new Tuple<string, string>("900028", "E"), 37},
   {new Tuple<string, string>("900029", "A"), 38},
   {new Tuple<string, string>("900002", "P"), 39},        
   {new Tuple<string, string>("900030", "FEMPA013.0"), 40}  
 };

 // Create an IEnumerable of all broken rules 
 var result = expected.Where(field => 
    !field.Key.Item2.Equals(
       actual.Substring(field.Value, field.Key.Item2.Length)))

 // Prints: 
 // [(900030, FEMPA013.0), 40]
 foreach (var res in result)
   Console.WriteLine(res);

Я уверен, что есть лучший способ решения этой проблемы. Кроме того, в нынешнем виде я не совсем удовлетворен этим решением, поскольку оно не дает мне фактического поля.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Вы должны создать класс для представления правила и иметь несколько вспомогательных методов в классе:

public class Rule {
    public string RuleName;
    public string Expected;
    public int StartPos;

    public bool IsMatch(string actual) => Field(actual) == Expected;
    public string Field(string actual) => actual.Substring(StartPos, Math.Min(Expected.Length, actual.Length-StartPos));
public override string ToString() => $"{{ {RuleName}: @{StartPos}=\"{Expected}\" }}";
}

Теперь вам может понадобиться List<Rule> для хранения правил:

var expected = new List<Rule> {
   new Rule { RuleName = "900052", Expected = "628", StartPos = 0 },
   new Rule { RuleName = "9000250", Expected = "IDENTREGISTER1", StartPos = 3 },
   new Rule { RuleName = "900092", Expected = "53004085616", StartPos = 17 },
   new Rule { RuleName = "900004", Expected = "P", StartPos = 28 },
   new Rule { RuleName = "900089", Expected = "30062010", StartPos = 29 },
   new Rule { RuleName = "900028", Expected = "E", StartPos = 37 },
   new Rule { RuleName = "900029", Expected = "A", StartPos = 38 },
   new Rule { RuleName = "900002", Expected = "P", StartPos = 39 },
   new Rule { RuleName = "900030", Expected = "FEMPA013.0", StartPos = 40 }
 };

И вы можете найти плохие правила и извлечь плохие поля:

string actual = "628IDENTREGISTER153004085616P30062010EAPFEMPA013.1";

var result = expected.Where(rule => !rule.IsMatch(actual)).Select(rule => new { rule, Actual = rule.Field(actual) });

foreach (var res in result)
    Console.WriteLine(res);

// Output is
// { rule = { 900030: @40="FEMPA013.0" }, Actual = FEMPA013.1 }
0 голосов
/ 16 мая 2018

По какой причине вы не можете просто обернуть правило вместе с проверяемой частью в кортеже?

Если нет, я бы сделал что-то вроде этого:

var result = from field in expected
             let inspected = actual.Substring(field.Value, field.Key.Item2.Length)
             where !field.Key.Item2.Equals(inspected)
             select (field, inspected);

Что тогдав приведенном выше примере выведите:

([(900030, FEMPA013.0), 40], FEMPA013.1)

Вы можете распаковать запись правила aнемного дальше в select, что-то вроде select (field.Key.Item1, field.Key.Item2, inspected);, и вы получите кортеж (RuleId, ожидаемый, фактический)

...