NEsper issue with regexp

本文关键字:regexp with issue NEsper | 更新日期: 2023-09-27 18:19:30

我已经被困在这里很长一段时间了,似乎用regex将问题归咎于不正确的NEsper行为。我写了一个简单的项目来重现这个问题,它可以从github上获得。

简而言之,NEsper允许我通过一组规则(类似SQL)来泵送消息(事件)。如果事件符合规则,NEsper将发出警报。在我的应用程序中,我需要使用正则表达式,但这似乎不起作用。

问题
我尝试了创建语句createPatterncreateEPL的两种方法,但它们并没有触发匹配事件,但是正则表达式和输入是由.NET Regex类匹配的。如果我将匹配值("127.0.0.5")传递给该语句而不是regex("''b''d{1,3}.''d{1,3}.''d{1,3}.''b"),则事件成功触发。

输入127.0.0.5==规则失败==every(Id123=TestDummy(值regexp'''b''d{1,3}''.''d{1,3}''.''d{1,3}''.[d{1.3}''b')//我想让它过去==规则通过==every(Id123=TestDummy(值regexp"127.0.0.5")

问题
有人能帮我做一个NEsper正则表达式匹配的例子吗?或者指出我在代码中的愚蠢错误。

代码
这是我的NEsper演示包装类

public class NesperAdapter
{
    public MatchEventSubscrtiber Subscriber { get; set; }
    internal EPServiceProvider Engine { get; private set; }
    public NesperAdapter()
    {
        //This call internally depend on log4net, 
        //will throw an error if log4net cannot be loaded 
        EPServiceProviderManager.PurgeDefaultProvider();
        //config
        var configuration = new Configuration();
        configuration.AddEventType("TestDummy", typeof(TestDummy).FullName);
        configuration.EngineDefaults.Threading.IsInternalTimerEnabled = false;
        configuration.EngineDefaults.Logging.IsEnableExecutionDebug = false;
        configuration.EngineDefaults.Logging.IsEnableTimerDebug = false;
        //engine
        Engine = EPServiceProviderManager.GetDefaultProvider(configuration);
        Engine.EPRuntime.SendEvent(new TimerControlEvent(TimerControlEvent.ClockTypeEnum.CLOCK_EXTERNAL));
        Engine.Initialize();
        Engine.EPRuntime.UnmatchedEvent += OnUnmatchedEvent;
    }
    public void AddStatementFromRegExp(string regExp)
    {
        const string pattern = "any (Id123=TestDummy(Value regexp '{0}'))";
        string formattedPattern = String.Format(pattern, regExp);
        EPStatement statement = Engine.EPAdministrator.CreatePattern(formattedPattern);
        //this is subscription
        Subscriber = new MatchEventSubscrtiber();
        statement.Subscriber = Subscriber;
    }
    internal void OnUnmatchedEvent(object sender, UnmatchedEventArgs e)
    {
        Console.WriteLine(@"Unmatched event");
        Console.WriteLine(e.Event);
    }
    public void SendEvent(object someEvent)
    {
        Engine.EPRuntime.SendEvent(someEvent);
    }
}

然后是订户和DummyType

public class MatchEventSubscrtiber
{
    public bool HasEventFired { get; set; }
    public MatchEventSubscrtiber()
    {
        HasEventFired = false;
    }
    public void Update(IDictionary<string, object> rows)
    {
        Console.WriteLine("Match event fired");
        Console.WriteLine(rows);
        HasEventFired = true;
    }
}
public class TestDummy
{
    public string Value { get; set; }
}

以及NUnit测试如果有一条注释nesper.AddStatementFromRegExp(regexp);行并取消注释//nesper.AddStatementFromRegExp(input);行,然后测试通过。但是我需要一个正则表达式。

//Match any IP address
[TestFixture(@"'b'd{1,3}'.'d{1,3}'.'d{1,3}'.'d{1,3}'b", "127.0.0.5")] 
public class WhenValidRegexpPassedAndRuleCreatedAndPropagated
{
    private NesperAdapter nesper;
    //Setup
    public WhenValidRegexpPassedAndRuleCreatedAndPropagated(string regexp, string input)
    {
        //check it is valid regexp in .NET
        var r = new Regex(regexp);
        var match = r.Match(input);
        Assert.IsTrue(match.Success, "Regexp validation failed in .NET");
        //create and start engine
        nesper = new NesperAdapter();
        //Add a rule, this fails with a correct regexp and a matching input
        //PROBLEM IS HERE 
        nesper.AddStatementFromRegExp(regexp);
        //PROBLEM IS HERE 
        //This works, but it is just input self-matching
        //nesper.AddStatementFromRegExp(input);
        var oneEvent = new TestDummy
        {
            Value = input
        };
        nesper.SendEvent(oneEvent);
    }
    [Test]
    public void ThenNesperFiresMatchEvent()
    {
        //wait till nesper process the event
        Thread.Sleep(100);
        //Check if subscriber has received the event
        Assert.IsTrue(nesper.Subscriber.HasEventFired,
            "Event didn't fire");
    }
}

NEsper issue with regexp

我调试这个问题已经有一段时间了,发现NEsper错误地处理

WHERE regexp 'foobar'语句

所以如果我有

SELECT*FROM MyType WHERE PropertyA regexp"一些有效的regexp"

NEsper使用"一些有效的正则表达式"执行字符串格式化和验证,并从正则表达式中删除重要的(和有效的)符号。这就是我自己解决的方法。不确定这是否是推荐的方法。

文件:com.espertech.esper.epl.expression.ExprRegexpNode

原因:我认为如何构建regexp取决于用户,这不应该是框架的一部分

// Inside this method
public object Evaluate(EventBean[] eventsPerStream, bool isNewData, ExprEvaluatorContext exprEvaluatorContext){...}
// Find two occurrences of
_pattern = new Regex(String.Format("^{0}$", patternText));
// And change to
_pattern = new Regex(patternText);

文件:com.espertech.esper.epl.parse.ASTConstantHelper

原因:所有字符串都需要Unescape,但跳过regexp,因为这会阻止有效的regexp并从中删除一些有效的符号。

// Inside this method  
public static Object Parse(ITree node){...}
// Find one occurrence of
case EsperEPL2GrammarParser.STRING_TYPE:
{
    return StringValue.ParseString(node.Text, requireUnescape);
}
// And change to
case EsperEPL2GrammarParser.STRING_TYPE:
{
bool requireUnescape = true;
if (node.Parent != null)
{
    if (!String.IsNullOrEmpty(node.Parent.Text))
    {
        if (node.Parent.Text == "regexp")
        {
            requireUnescape = false;
        }
    }
}
return StringValue.ParseString(node.Text, requireUnescape);
}

文件:com.espertech.esper.type.StringValue

原因:取消捕获所有字符串,但正则表达式值除外

// Inside this method  
public static String ParseString(String value){...}
// Change from
public static String ParseString(String value)
{
    if ((value.StartsWith("'"")) & (value.EndsWith("'"")) || (value.StartsWith("'")) & (value.EndsWith("'")))
    {
        if (value.Length > 1)
        {               
            if (value.IndexOf('''') != -1)
            {
                return Unescape(value.Substring(1, value.Length - 2));
            }
            return value.Substring(1, value.Length - 2);
        }
    }
    throw new ArgumentException("String value of '" + value + "' cannot be parsed");
}   
// Change to
public static String ParseString(String value, bool requireUnescape = true)
{
    if ((value.StartsWith("'"")) & (value.EndsWith("'"")) || (value.StartsWith("'")) & (value.EndsWith("'")))
    {
        if (value.Length > 1)
        {
            if (requireUnescape)
            {
                if (value.IndexOf('''') != -1)
                {
                    return Unescape(value.Substring(1, value.Length - 2));
                }
            }
            return value.Substring(1, value.Length - 2);
        }
    }
    throw new ArgumentException("String value of '" + value + "' cannot be parsed");
}