NEsper проблема с регулярным выражением

Я застрял здесь на некоторое время и, похоже, решил проблему с неправильным поведением NEsper с регулярным выражением. Я написал простой проект, чтобы воспроизвести проблему, и он доступен на github.

Короче говоря, NEsper позволяет мне перекачивать сообщения (события) с помощью набора правил (подобных SQL). Если событие соответствует правилу, NEsper выдает предупреждение. В моем приложении мне нужно использовать регулярное выражение и это, похоже, не работает.

Проблема
Я попробовал оба подхода создание инструкций createPattern и createEPL, и они не запускают событие совпадения, однако регулярное выражение и ввод сопоставляются классом .NET Regex. Если вместо регулярного выражения ("\b\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\b") я передаю соответствующее значение (" 127.0.0.5") к оператору, событие успешно запускается.

INPUT 
127.0.0.5

==RULE FAIL==
every (Id123=TestDummy(Value regexp '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'))
// and I want this to pass

==RULE PASS==
every (Id123=TestDummy(Value 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");
    }
}

person oleksii    schedule 04.01.2012    source источник


Ответы (1)


Я отлаживал эту проблему в течение некоторого времени и обнаружил, что NEsper неправильно обрабатывает

WHERE regexp 'foobar' заявление

Итак, если у меня есть

SELECT * FROM MyType WHERE PropertyA регулярное выражение 'какое-то допустимое регулярное выражение'

NEsper выполняет форматирование и проверку строки с помощью «некоторого допустимого регулярного выражения» и удаляет важные (и допустимые) символы из регулярного выражения. Вот как я исправил это для себя. Не уверен, что это рекомендуемый подход.

Файл: com.espertech.esper.epl.expression.ExprRegexpNode

Причина: я думаю, что пользователю решать, как строить регулярное выражение, это не должно быть частью структуры.

// 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

Причина: requireUnescape для всех строк, но пропустить регулярное выражение, поскольку это тормозит допустимое регулярное выражение и удаляет из него некоторые допустимые символы.

// 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");
}   
person oleksii    schedule 12.01.2012