0

如何确定给定是否int对应于给定的“模式”。“模式”可以由 int 或 int 范围组成。

这是该方法的签名。

    //Eg of pattern 
    // 10,12,14,16
    // [10-20];21;23
    public bool IsInPattern(int inputToTest, string pattern)
    {
        //Todo
    }

下面的模式被定义为一个字符串,其中包含一个由';'分隔的内部模式列表。内部模式可以是 int 或范围 [lowerBound-upperBound]。

我相信可以通过正则表达式实现,但我没有成功。另外,我更喜欢比if subPattern.StartWith('[') then lowerBound = subPattern.Substring等更优雅的解决方案......

4

6 回答 6

2

我会把它写成两种方法而不是模式。

public bool IsInSequence(int inputToTest, IEnumerable<int> sequence)
{
    return sequence.Contains(inputToTest);
}

public bool IsInRange(int inputToTest, int start, int end)
{
    return inputToTest>= start && inputToTest<=end ;
}
于 2013-10-28T09:31:30.713 回答
1

您可以使用这样的简单解析。

public bool IsInPattern(int inputToTest, string pattern)
{
    var numbers = new List<int>();
    var tokens = pattern.Split(new []{",", " ", "or"}, 
                               StringSplitOptions.RemoveEmptyEntries);
    bool to_flag = false;
    foreach(var t in tokens)
    {
        int n;
        if (Int32.TryParse(t, out n))
        {
            if (to_flag) 
                numbers.AddRange(Enumerable.Range(numbers.Last() + 1, 
                                                  n - numbers.Last()));
            else 
                numbers.Add(n);

            to_flag = false;
        }
        else if (t == "to") to_flag = true;
        else throw new Exception("invalid pattern");
    }
    return numbers.Contains(inputToTest);
}

和一个测试:

IsInPattern(11, "10,12,14,16"); // false
IsInPattern(12, "10,12,14,16"); // true
IsInPattern(11, "10 to 20 or 21 or 23");// true
IsInPattern(22, "10 to 20 or 21 or 23");// false
于 2013-10-28T09:39:05.263 回答
0

这是一个具有不同 IPatternInterpretter 实现的解决方案。PatternInterpretter 的 Interpret 方法输入字符串表达式,并通过处理字符串表达式返回其 Func 表示。

您应该为每种不同类型的模式字符串实现 IPatternInterpretter。毕竟,您可以编写一个 PatternInterpretterFactory 来输入单个字符串模式并决定实例化哪个解释器。

class Program
{
    static void Main(string[] args)
    {
        const string commaSeperatedPattern = "10,12,14,16";
        const string literallyExpressedPattern = "10 to 20 or 21 or 23";

        int input = 10;

        var commaSeperatedFunc = new CommaSeperatedPatternInterpretter().Interpret(commaSeperatedPattern);
        var literallyExpressedFunc = new LiterallyExpressedPatternInterpretter().Interpret(literallyExpressedPattern);

        Console.WriteLine(string.Format("CommaSeperatedResult: {0} \nLiterallyExpressedResult: {1}",
                                        commaSeperatedFunc(input),
                                        literallyExpressedFunc(input)));
        Console.ReadKey();
    }
}



public interface IPatternInterpretter
{
    Func<int, bool> Interpret(string pattern);
}

/// <summary>
/// Patterns like "10,12,14,16"
/// </summary>
public class CommaSeperatedPatternInterpretter : IPatternInterpretter
{
    public Func<int, bool> Interpret(string pattern)
    {
        Func<int, bool> result = (input) => pattern.Split(',').Select(x => int.Parse(x.Trim())).Contains(input);
        return result;
    }
}

/// <summary>
/// Patterns like "10 to 20 or 21 or 23"
/// </summary>
public class LiterallyExpressedPatternInterpretter : IPatternInterpretter
{
    public Func<int, bool> Interpret(string pattern)
    {
        Func<int, bool> result = (x) => false;
        List<string> items = pattern.Split(' ').Select(x => x.Trim().ToLower()).ToList();

        var ors = new List<int>();
        var intervals = new List<Array>();
        for (int i = 0; i < items.Count; i++)
        {
            var item = items[i];

            if (item.Equals("or") && i < items.Count-1)
            {
                ors.Add(int.Parse(items[i + 1]));
            }
            else if (item.Equals("to") && i < items.Count-1 && i > 0)
            {
                intervals.Add(new int[] {int.Parse(items[i - 1]), int.Parse(items[i + 1])});
            }
        }
        return x => ors.Contains(x) || intervals.Any(i => x > (int) i.GetValue(0) && x < (int) i.GetValue(1));
    }
}
于 2013-10-30T09:15:02.117 回答
0

当我需要检查某些值是否满足不同的条件时,我喜欢使用规范模式。规格如下:

public interface ISpecification<T>
{
    bool IsSatisfiedBy(T value);
}

对于每组条件,您创建不同的规范类。在这里,您将需要范围规范(我将int用作泛型类型以简化事情):

public class RangeSpecification : ISpecification<int>
{
    private readonly int _from;
    private readonly int _to;

    public RangeSpecification(int from, int to)
    {
        _to = to;
        _from = from;
    }

    public bool IsSatisfiedBy(int value)
    {
        return _from <= value && value <= _to;
    }
}

以及值列表的规范(我们也可以将单个值视为列表规范):

public class InSpecification : ISpecification<int>
{
    private readonly int[] _values;

    public InSpecification(params int[] values)
    {
        _values = values;
    }

    public bool IsSatisfiedBy(int value)
    {
        return _values.Contains(value);
    }
}

这已经足以测试以下条件:

var rangeSpec = new RangeSpecification(10, 15);
var is13inRange = rangeSpec.IsSatisfiedBy(13); // true
var is20inRange = rangeSpec.IsSatisfiedBy(20); // false
var inSpec = new InSpecification(1,2,5,8);
var is13inList = inSpec.IsSatisfiedBy(13); // false

但是为了构建更有趣的条件,您需要实现条件逻辑:

public class OrSpecification<T> : ISpecification<T>
{
    private readonly ISpecification<T> _left;
    private readonly ISpecification<T> _right;

    public OrSpecification(ISpecification<T> left, ISpecification<T> right)
    {
        _right = right;
        _left = left;
    }

    public bool IsSatisfiedBy(T value)
    {
        return _left.IsSatisfiedBy(value) || _right.IsSatisfiedBy(value);
    }
} 

该规范将帮助我们构建 OR 条件以检查值是否满足任何提供的规范。我还使用扩展方法来构建规范:

public static class SpecificationExtensions
{
    public static ISpecification<T> Or<T>(
        this ISpecification<T> left, ISpecification<T> right)
    {
        return new OrSpecification<T>(left, right);
    }
}

现在我们可以构建类似的东西:

var spec = new RangeSpecification(10, 15).Or(new InSpecification(1,2,5,8));
var result = spec.IsSatisfiedBy(8); // true

我们现在需要的是从您的字符串中解析规范:

public class SpecificationParser
{
    public static ISpecification<int> Parse(string input)
    {
        var parts = input.Split(';');
        return parts.Aggregate(ParseSpec(parts[0]), 
                               (spec, s) => spec.Or(ParseSpec(s)));
    }

    private static ISpecification<int> ParseSpec(string s)
    {
        var match = Regex.Match(s, @"\[(\d+)-(\d+)\]");
        if (match.Success)
        {
            int from = Int32.Parse(match.Groups[1].Value);
            int to = Int32.Parse(match.Groups[2].Value);
            return new RangeSpecification(from, to);
        }

        return new InSpecification(s.Split(',').Select(Int32.Parse).ToArray());
    }
}

而已。现在您可以从字符串解析规范并检查值是否满足它:

var spec1 = SpecificationParser.Parse("10, 12, 14, 16");
spec1.IsSatisfiedBy(11); // false

var spec2 = SpecificationParser.Parse("[10-20];21;23,25");
spec2.IsSatisfiedBy(9); // false
spec2.IsSatisfiedBy(19); // true
spec2.IsSatisfiedBy(22); // false
于 2013-10-28T10:50:24.743 回答
0

你可以尝试这样的事情(这是从头开始的,所以如果不修改它可能无法工作):

public bool IsInPattern(int inputToTest, string pattern)
{
    if (pattern.Contains(","))
        return pattern.Split(',').Contains(inputToTest.ToString());
    else
    {
        var temp = pattern.Split(';');
        if (temp.Contains(inputToTest.ToString()))
            return true;
        else
        {
            temp = temp.RemoveAll(x => !x.Contains("-"));
            foreach (var x in temp)
            {
                string[] a = x.Split("-").Select(x => x.Trim('[',']')).ToArray();
                if (IsInRange(inputToTest, int.Parse(a[0]), int.Parse(a[1])))
                    return true;
            }
        }
    }
    return false;
}

public bool IsInRange(int inputToTest, int start, int end)
{
    return inputToTest >= start && inputToTest <=end;
}
于 2013-10-28T09:41:40.983 回答
0

可能是这样的:

pattern.Split(',').Where(sub=>sub == inputToTest.ToString())

如果有一个范围或只有任意整数序列,这种方式完美地工作,由一些预定义的分隔符分隔(在这种具体情况下)

于 2013-10-28T09:27:21.877 回答