Podmínka jak text   zodpovězená otázka

Algoritmy, .NET

Dobrý den,

rád bych se poradil jak zpracovávat textové vyjádření nějaké libovolné podmínky. Zadává ji uživatel do tabulky aplikace.

Příklad:

podmínka: 100<value<200

vyhodnocení: jestli požadovaná hodnota (kterou zadá uživatel) se nachází v rozpětí, apod.

Hodnota "value" může být jakákoliv a nesouvisí nijak s aplikací (nepochází z aplikace).

Jde tedy o to pouze ověřit jestli, když uživatel zadá hodnotu "value", vyhovuje jeho podmínce.

Předem děkuji

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jo, tak to si budete muset naparsovat sám.

Doporučuji celý výraz od uživatele naparsovat a reprezentovat jako nějaký objekt, jinak se to bude dělat dost těžko, pokud tam budou závorky a složitější operátory). Ale otázkou je, jestli to není kanón na vrabce.

Co přesně v podmínkách má být?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Podmínky by měly být hodně jednoduché a mělo bych jich být jen pár. V podstatě by se mělo jednat hlavně o obdobu uvedeného příkladu.

Ještě přidám upřesnění pro jasné pochopení problému:

uživatel si nadefinuje nějaká kritéria (viz podmínka v úvodu) a následně sleduje u určitých případů, jestli tato podmínka byla splněna nebo ne. Účelem je záznam informací pro následné vyhodnocování.

Patrně hlavně by šlo o toto:

parametr ......údaj k porovnávání (předdefinovaná hodnota uživatelem)

hodnota ...... sledovaná hodnota (opět externí údaj uživatele)

hodnota = parametr

hodnota < parametr

hodnota > parametr

parametr1 < hondnota < parametr2

Chtěl jsem se ubírat obecnějším směrem, ale patrně to bude muset být více omezené a předdefinované.

Díky za odpovědi

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pokud je tvarů podmínek jen takhle málo, nestačí na to vytvořit nějaké comboboxy? Musí to uživatel zadávat jako text?

A pokud ano, tak si to můžete snadno naparsovat sám pomocí funkcí IndexOf a Substring na řetězcích, není to nic těžkého. Případně použít regulární výrazy, ale tomu bych se raději vyhnul.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Lze to řešit například vytvořením, zkompilováním a spuštěním jednoduché C# třídy, která zadanou podmínku vyhodnotí.

Podívejte se na tento článek - http://www.codeproject.com/KB/cs/evalcsc...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Bohužel výrazy typu a < b < c to už nezkousne.

Navíc je to kanón na vrabce a v případě, že se bude vyhodnocování opakovat, zaděláte si na slušný memory leak, protože načtené assembly se z paměti jen těžko vyhazují.

A kompilace a dynamické načtení assembly za běhu trvá řídově stovky milisekund, což z hlediska výkonnosti také není úplně ideální.

Pokud má být aplikace něco rozumného a ne jen jednoúčelová utilitka, pak je toto řešení naprosto nevhodné.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Memory Leak? Já tam nevidím nic, co by dřív nebo později automaticky neuklidil Garbage Collector.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Bohužel pokud to napíšete hloupě a každé vyhodnocení výrazu zkompiluje a dynamicky načte novou assembly, tak je to problém, protože GC nesebere assembly, jelikož neví, že ten kód nikdy nebude potřeba (což z principu vědět nemůže).

Dalo by se to třeba naloadovat do jiné aplikační domény a pak ji zase zrušit, ale je to je ještě větší kanón na vrabce.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Proč by to nezkouslo výrazy typu a < b < c? Generátor C# třídy lze například upravit, že dostane libovolný počet parametrů, ze kterých potom udělá property a mohu je ve vyhodnocovaném výrazu použít.

S výkonovou a paměťovou náročností máte pravdu, ale netuším v jaké aplikaci to chce tazatel použít. Nicméně je určitě dobré na to upozornit a udělat nějaký jednoduchý zátěžový test.

V komentářích pod článkem je zmíněné ještě jedno řešení, které je výkonově mnohem lepší, protož využívá JScriptovou funkci Eval. V tomto případě se v paměti zkompiluje pouze jedna assembly a ta se potom opakovaně používá.

using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.JScript;

namespace Expressions
{
  public class JScriptEvaluator
  {
    public static int EvalToInteger(string statement)
    {
      string s = EvalToString(statement);
      return int.Parse(s.ToString());
    }

    public static string EvalToString(string statement)
    {
      object o = EvalToObject(statement);
      return o.ToString();
    }

    public static object EvalToObject(string statement)
    {
      return _evaluatorType.InvokeMember(
                "Eval",
                BindingFlags.InvokeMethod,
                null,
                _evaluator,
                new object[] { statement }
            );
    }

    static JScriptEvaluator()
    {
      CodeDomProvider provider = new Microsoft.JScript.JScriptCodeProvider();

      CompilerParameters parameters = new CompilerParameters();
      parameters.GenerateInMemory = true;

      CompilerResults results = provider.CompileAssemblyFromSource(parameters, _jscriptSource);

      Assembly assembly = results.CompiledAssembly;
      _evaluatorType = assembly.GetType("Evaluator.Evaluator");

      _evaluator = Activator.CreateInstance(_evaluatorType);
    }

    private static object _evaluator = null;
    private static Type _evaluatorType = null;
    private static readonly string _jscriptSource =

        @"package Evaluator
                  {
                     class Evaluator
                     {
                           public function Eval(expr : String) : String
                           {
                              return eval(expr);
                           }
                     }
                  }";
  }
}

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dodatek:

Provedl jsem jednoduchý test rychlosti, kde jsem 1000x nechal vyhodnotit výraz "2+5".

Verze s JScript: 0.04 s

Verze s C#: 70.19 s

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback