如何确定给定的int
是否对应于给定的“模式”。 'pattern'可以由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
等更优雅的解决方案......
答案 0 :(得分: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 ;
}
答案 1 :(得分: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
答案 2 :(得分:0)
可能是这样的:
pattern.Split(',').Where(sub=>sub == inputToTest.ToString())
如果存在范围或只有任意整数序列,这种方式完美有效,由一些预定义的分隔符(在这个具体情况下)分隔
答案 3 :(得分: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;
}
答案 4 :(得分:0)
当我需要检查某些值满足不同条件时,我喜欢使用Specification Pattern。规格如下:
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());
}
}
就是这样。现在你可以解析string中的规范并检查value是否满足它:
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
答案 5 :(得分: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));
}
}