为了突出显示单个字符串中的多个搜索文本元素,我有一个例程计算要在字符串本身中突出显示的范围。
例如,如果我在字符串&#34中搜索his+is
字符串;这是我的错误测试"我得到了高亮范围[1,3]
,[2,3]
,[5,6]
和[12,13]
。
所以我想要的结果是[1,3]
,[5,6]
和[12,13]
。
是否有一般方法从上面的列表中提取非重叠范围?或事件更好,是否有特定于字符串的方式来获取这些?
答案 0 :(得分:1)
如果你想以文本为基础,这取决于你可能的搜索模式的复杂性(正则表达式?)。如果你指定了这个,我很乐意帮你解决。
答案 1 :(得分:0)
高效你有什么理解?快速?最少的内存使用? Mantainable代码?
有很多方法可以解决这个问题,其中一些方法似乎需要很多代码,但也许不错。例如,请考虑以下方法:
public struct Interval<T> where T: IComparable<T>
{
public T LowerBound { get; }
public T UpperBound { get; }
public Interval(T lowerBound, T upperBound)
{
Debug.Assert(upperBound.CompareTo(lowerBound) > 0);
LowerBound = lowerBound;
UpperBound = upperBound;
}
public static bool AreOverlapping(Interval<T> first, Interval<T> second) =>
first.UpperBound.CompareTo(second.LowerBound) > 0 &&
second.UpperBound.CompareTo(first.LowerBound) > 0;
public static Interval<T> Union(Interval<T> first, Interval<T> second)
{
Debug.Assert(AreOverlapping(first, second));
return new Interval<T>(Min(first.LowerBound, second.LowerBound),
Max(first.UpperBound, second.UpperBound));
}
public override string ToString() => $"[{LowerBound}, {UpperBound}]";
private static T Min(T t1, T t2)
{
if (t1.CompareTo(t2) <= 0)
return t1;
return t2;
}
private static T Max(T t1, T t2)
{
if (t1.CompareTo(t2) >= 0)
return t1;
return t2;
}
}
现在,我们提取非重叠区间的方法是:
public static IEnumerable<Interval<T>> GetOverlappingIntervals<T>(this IEnumerable<Interval<T>> intervals)
where T : IComparable<T>
{
var stack = new Stack<Interval<T>>();
foreach (var interval in intervals.OrderBy(i => i.LowerBound))
{
if (stack.Count == 0)
{
stack.Push(interval);
}
else
{
var previous = stack.Peek();
if (Interval<T>.AreOverlapping(interval, previous))
{
stack.Pop();
stack.Push(Interval<T>.Union(interval, previous));
}
else
{
stack.Push(interval);
}
}
}
return stack;
}
请注意,此解决方案不会执行相邻间隔的并集,不确定这是否是您想要的。
这个解决方案难以理解吗?是的,代码几乎是自我解释的。它效率最高吗?好吧,可能不是,但谁关心它是否“足够”并且它符合你的性能目标。如果没有,那么就开始优化它。