_

Zliczanie nazwanego osprzętu

Forum poświęcone flagowemu produktowi oraz aplikacjom pochodnym Autodesku. To jedyne forum mające w tytule nazwę programu, a to ze względu na jego olbrzymią popularność w Polsce. Można tutaj umieszczać również posty z ogólnie pojętej tematyki "Kreślarskie 2D".

Zliczanie nazwanego osprzętu

Postprzez badziewiak » wrz 27, 2011 01:46

Witajcie
Postanowilem uproscic zliczanie np. rur ochronnych z sieci zewnetrznych, tras kablowych z inst. wew. itp., wiec popelnilem takiego DLLa, ktory bedzie standardowym wyposazeniem moich zabawek rysujacych powyzsze instalacje. Ma to zliczac rzeczy zapisane w przykladowym formacie:

DVK160
3xDVK160
3x(DVK160)
3x(DVK160+2xDVK75)
3xDVK160+DVK75
3x(DVK160+2x(DVK110+DVK75))
3x(DVK160+2x(DVK110+DVK75)x3+DVK50)

Milczące założenia:
1. Stała nie może zaczynać się cyfrą ani zawierać "x"

Takie zapisy jak powyzsze to moje cos wytrzymalo. Jak macie ochote, to potestujcie, moze cos jeszcze wyskoczy.
Ponizej zrodlo, w zalaczniku binarki. Wymaga to .NET 3.5.
Kod: Zaznacz cały
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

public static class RKparserMatematyczny
{
   //Celem tego algorytmu jest zsumowanie przykładowych zapisów:
   //DVK160
   //3xDVK160
   //3x(DVK160)
   //3x(DVK160+2xDVK75)
   //3xDVK160+DVK75
   //3x(DVK160+2x(DVK110+DVK75))
   //3x(DVK160+2x(DVK110+DVK75)x3+DVK50)
   //Milczące założenia:
   //1. Stała nie może zaczynać się cyfrą ani zawierać "x"

   static Regex regExCyfra = new Regex( "\\d" );
   static Regex regExLitera = new Regex( "[^\\d\\(\\)\\+\\.\\,x]" );
   static Regex regExLiteraLubCyfra = new Regex( "[^\\(\\)\\+x]" );
   static int zagniezdzenieNawiasow = 0;
   
   //Główna funkcja
   public static void zliczOsprzet( List<string> tekstyColl, out List<KeyValuePair<string, double>> osprzetZliczonyColl   )
   {
      zagniezdzenieNawiasow = 0;
      osprzetZliczonyColl = new List<KeyValuePair<string, double>>();
      List<KeyValuePair<string, double>> daneWy = new List<KeyValuePair<string, double>>();
      Dictionary<string, int> osprzetZliczonyDict = new Dictionary<string, int>();
      List<int> indeksy = new List<int>();

      //Przetwarzać wszystkie tekstyColl
      foreach( string tekst in tekstyColl )
      {
         int nrZnaku = 0;
         zlicz( tekst, ref nrZnaku, 1, daneWy );
         if( zagniezdzenieNawiasow > 0 )
            throw new RKparserMatematycznyExceptionBladSkladni( "Nie zgadza się ilość nawiasów otwierających i zamykających!" );

         int indeks = 0;
         foreach( KeyValuePair<string, double> para in daneWy )
         {
            //Czy taki sprzęt już jest?
            if( osprzetZliczonyDict.TryGetValue( para.Key.ToLower(), out indeks ) )
            {
               //Jest - tylko dodać.
               KeyValuePair<string, double> _para = new KeyValuePair<string, double>( osprzetZliczonyColl[indeks].Key, osprzetZliczonyColl[indeks].Value + para.Value );
               osprzetZliczonyColl[indeks] = _para;
            }   //if( osprzetZliczonyDict.TryGetValue( para.Key.ToLower(), out indeks ) )
            else
            {
               //Nie ma takiej pozycji - dodać.
               KeyValuePair<string, double> _para = new KeyValuePair<string, double>( para.Key, para.Value );
               osprzetZliczonyColl.Add( _para );
               osprzetZliczonyDict.Add( para.Key, indeksy.Count );
               indeksy.Add( indeksy.Count );
            }   //else if( osprzetZliczonyDict.TryGetValue( para.Key.ToLower(), out indeks ) )
         }   //foreach( KeyValuePair<string, double> para in daneWyLokalne )

      }   //foreach( string tekst in tekstyColl )
   }   //public static void zliczOsprzet( string wyrazenie, List<KeyValuePair<string, double>> daneWy   )

   public static void testujWyrazenie( string wyrazenie, out List<KeyValuePair<string, double>> osprzetZliczonyColl )
   {
      List<string> tekstyColl = new List<string>();
      tekstyColl.Add( wyrazenie );
      zliczOsprzet( tekstyColl, out osprzetZliczonyColl );
   }   //public static void testujWyrazenie( string wyrazenie )

   static void zlicz( string wyrazenie, ref int nrZnaku, double mnoznikWejsciowy, List<KeyValuePair<string, double>> daneWy )
   {
      string znak = wyrazenie.Substring( nrZnaku, 1 );
      double mnoznikBiezacy = 1;
      while( nrZnaku < wyrazenie.Length )
      {
         //Czy to litera?
         if( regExLitera.IsMatch( znak ) )
         {
            //Pobrać stałą
            string stala = pobierzStala( wyrazenie, ref nrZnaku );
            //Czy za stałą jest znak mnożenia "x"?
            if( nrZnaku < wyrazenie.Length )
            {
               znak = wyrazenie.Substring( nrZnaku, 1 );
               if( znak == "x" )
                  mnoznikBiezacy *= pobierzMnoznik( wyrazenie, ref nrZnaku );
               //Przemnożyć stałą przez mnożnik bieżący x mnożnik wejściowy
               //Dodać przemnoż. stałą do wyników
            }   //if( nrZnaku < wyrazenie.Length )
            daneWy.Add( new KeyValuePair<string, double>( stala.Trim(), mnoznikBiezacy * mnoznikWejsciowy ) );
            //Bieżący mnożnik = 1
            mnoznikBiezacy = 1;
            if( nrZnaku < wyrazenie.Length )
            {
               //Stała może zostać przerwana przez:
               //+) i chyba więcej nic.
               //Tu nie trzeba inkrementować numeru znaku,
               //bo został ustawiony podczas pobierania stałej.
               //Wymnożyć stałą przez bieżący mnożnik.
               //Po wymnożeniu zresetować mnożnik na 1.

               //Coś pozostało - dopuszczalne tylko "+" i ")"
               znak = wyrazenie.Substring( nrZnaku, 1 );
               if( znak != "+" && znak != ")" )
                  throw new RKparserMatematycznyExceptionBladSkladni( "Za typem osprzętu jest dopuszczalny tylko \"+\" lub \")\", a jest " + znak +
                                                                                                   "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
               continue;
            }   //if( nrZnaku < wyrazenie.Length )
            else
               break;
         }   //if( regExLitera.IsMatch( znak ) )
         else if( regExCyfra.IsMatch( znak ) )
         {
            //Jest cyfra - pobrać mnożnik
            //Za mnożnikiem może wystąpić
            //tylko stała lub (
            //Tu nie trzeba pobierać kolejnego znaku,
            //bo został ustawiony w stałej.
            mnoznikBiezacy = pobierzMnoznik( wyrazenie, ref nrZnaku );
            //Bieżący mnożnik zostanie zmodyfikowany.
            //Następna stała lub nawias będzie
            //potraktowana tym mnożnikiem.
            //Po użyciu mnożnik zostanie ustawiony na 1
            //Tu nie trzeba inkrementować numeru znaku,
            //bo został ustawiony w trakcie pobierania mnożnika.
            //Nie inkrementować numeru znaku!!!
            znak = wyrazenie.Substring( nrZnaku, 1 );
            //Jeśli nie jest to litera ani "(", to błąd składni
            if( !regExLitera.IsMatch( znak ) && znak != "(" )
               throw new RKparserMatematycznyExceptionBladSkladni( "Za symbolem mnożenia lub luźną liczbą jest dopuszczalny tylko \"(\" lub typ osprzętu, a jest " + znak +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
            continue;
         }   //else if( regExCyfra.IsMatch( znak ) )
         else if( znak == "(" )
         {
            //Jest nawias otwierający
            //Nowy kontener na zliczone dane
            List<KeyValuePair<string, double>> daneWyLokalne = new List<KeyValuePair<string, double>>();
            zagniezdzenieNawiasow++;
            //Przeskoczyć nawias
            nrZnaku++;
            if( nrZnaku >= wyrazenie.Length )
               throw new RKparserMatematycznyExceptionUrwaneWyrazenie( "Niekompletny opis osprzętu! Nawias został otwarty, ale nic w nim nie ma!" +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
            znak = wyrazenie.Substring( nrZnaku, 1 );
            //Wywołać się rekurencyjnie
            //z argumentem
            //bieżący mnożnik x mnożnik wejściowy
            //oraz nowym kontenerem na dane
            zlicz( wyrazenie, ref nrZnaku, mnoznikBiezacy * mnoznikWejsciowy, daneWyLokalne );
            //Wyrażenie zostało zakończone. Jedynym dopuszczalnym powodem jest ")"

            mnoznikBiezacy = 1;
            if( nrZnaku < wyrazenie.Length )
            {
               znak = wyrazenie.Substring( nrZnaku, 1 );
               if( znak != ")" )
                  throw new RKparserMatematycznyExceptionBladSkladni( "Za wyrażeniem w nawiasie musi być \")\", a jest " + znak +
                                                                                                   "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
               //Za nawiasem zamykającym może być "+" lub ")" "xNN"
               nrZnaku++;
               if( nrZnaku < wyrazenie.Length )
               {
                  znak = wyrazenie.Substring( nrZnaku, 1 );
                  if( znak == "x" )
                  {
                     //Pobrać mnożnik, wymnożyć przez niego zawartość nawiasu i dodać do danych wyjściowych
                     mnoznikBiezacy = pobierzMnoznik( wyrazenie, ref nrZnaku );
                     znak = wyrazenie.Substring( nrZnaku, 1 );
                  }   //if( znak == "x" )
               }   //if( nrZnaku < wyrazenie.Length && znak == "x" )
            }   //if( nrZnaku < wyrazenie.Length )
            //Przepisywać dane z nawiasu do danych
            //nadrzędnych, z przemnożeniem przez mnożnik
            foreach( KeyValuePair<string, double> para in daneWyLokalne )
            {
               daneWy.Add( new KeyValuePair<string, double>( para.Key, para.Value * mnoznikBiezacy ) );
            }   //foreach( KeyValuePair<string, double> para in daneWyLokalne )
            mnoznikBiezacy = 1;
            //Za nawiasem zamykającym może być tylko kolejny nawias zamykający lub "+"
            if( nrZnaku < wyrazenie.Length )
            {
               if( znak != ")" && znak != "+" && znak != "x" )
                  throw new RKparserMatematycznyExceptionBladSkladni( "Za nawiasem zamykający może być \")\" lub \"+\" lub \"x\", a jest " + znak +
                                                                                                   "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
               continue;
            }   //if( nrZnaku < wyrazenie.Length )
            //Analiza stopnia zagnieżdżenia nawiasów ma być w funkcji nadrzędnej, która wywołuję tą funkcję.
            break;   //już nic nie ma
         }   //else if( znak == "(" )
         else if( znak == "+" )
         {
            //Jest plus, tylko przeskoczyć go i kontynuować analizę.
            nrZnaku++;
            if( nrZnaku >= wyrazenie.Length )
               throw new RKparserMatematycznyExceptionUrwaneWyrazenie( "Niekompletny opis osprzętu! Za znakiem \"+\" coś musi jeszcze być, a nic nie ma!" +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
            znak = wyrazenie.Substring( nrZnaku, 1 );
            continue;
         }   //else if( znak == "+" )
         else if( znak == ")" )
         {
            //Nawias zamykający - zatrzymanie analizy tej części wyrażenia
            zagniezdzenieNawiasow--;
            break;
         }   //else if( znak == ")" )
      }   //while( nrZnaku < wyrazenie.Length )
   }   //public static void zlicz( string wyrazenie, ref int nrZnaku, List<KeyValuePair<string, double>> daneWy )

   //static List<KeyValuePair<string, double>> wezWyrazenie( string wyrazenie, ref int nrZnaku, List<KeyValuePair<string,double>> wynik )
   //{

   //}   //static List<KeyValuePair<string, double>> wezWyrazenie( string wyrazenie, ref int nrZnaku, List<KeyValuePair<string,double>> wynik )

   public static string pobierzStala( string wyrazenie, ref int nrZnaku )
   {
      string wynik = "";
      StringBuilder sb = new StringBuilder();
      for( ; nrZnaku < wyrazenie.Length; nrZnaku++ )
      {
         //Jest litera lub cyfra?
         string znak = wyrazenie.Substring( nrZnaku, 1 );
         if( regExLiteraLubCyfra.IsMatch( znak ) )
         {
            //Tak, dodać do wyniku
            sb.Append( znak );
         }   //if( regExLiteraLubCyfra.IsMatch( wyrazenie.Substring( nrZnaku, 1 ) ) )
         else
         {
            //Koniec stałej - wynocha
            break;
         }   //else if( regExLiteraLubCyfra.IsMatch( znak ) )
      }   //for( int nrZnaku = 0; nrZnaku < wyrazenie.Length; nrZnaku++ )
      wynik = sb.ToString();
      return wynik;
   }   //static string pobierzStala( string wyrazenie, ref int nrZnaku )

   public static int pobierzMnoznik( string wyrazenie, ref int nrZnaku )
   {
      int wynik = 1;
      string znak = wyrazenie.Substring( nrZnaku, 1 );
      bool xZproodu = false;
      do
      {
         StringBuilder sb = new StringBuilder();
         //Jeśli jest "x" , to przeskoczyć
         if( znak == "x" )
         {
            xZproodu = true;
            nrZnaku++;
         }   //if( znak == "x" )
         for( ; nrZnaku < wyrazenie.Length; nrZnaku++ )
         {
            //Jest cyfra?
            znak = wyrazenie.Substring( nrZnaku, 1 );
            if( regExCyfra.IsMatch( znak ) )
            {
               //Tak, dodać do wyniku
               sb.Append( znak );
            }   //if( regExLiteraLubCyfra.IsMatch( wyrazenie.Substring( nrZnaku, 1 ) ) )
            else
            {
               if( sb.Length > 0 )
               {
                  wynik *= Convert.ToInt32( sb.ToString() );
                  //Koniec liczby - czy "x"?
                  if( znak == "x" )
                     break;
                  if( znak != "x" && znak != "(" && znak != "+" )
                     throw new RKparserMatematycznyExceptionBladSkladni( "Spodziewano się znaku mnożenia \"x\" lub \"(\", a jest " + znak );
                  if( !xZproodu && znak != "x" )
                     throw new RKparserMatematycznyExceptionBladSkladni( "Jest luźna liczba bez znaku mnożenia \"x\"" +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
                  return wynik;
               }   //if( sb.Length > 0 )
               else
               {
                  return wynik;
               }
            }   //else if( regExCyfra.IsMatch( znak ) )
            if( nrZnaku == wyrazenie.Length - 1 )
               wynik *= Convert.ToInt32( sb.ToString() );
         }   //for( int nrZnaku = 0; nrZnaku < wyrazenie.Length; nrZnaku++ )
         
      }
      while( nrZnaku < wyrazenie.Length && wyrazenie.Substring( nrZnaku, 1 ) == "x" );
      //Jeśli jest tylko sama liczba bez znaku "x", potraktować to jako błąd.

      return wynik;
   }   //static int pobierzMnoznik( string wyrazenie, ref int nrZnaku )

   public class RKparserMatematycznyExceptionUrwaneWyrazenie : System.Exception
   {
      public RKparserMatematycznyExceptionUrwaneWyrazenie( string Message ) : base( Message )
      {
         this.Source = "RKparserMatematyczny";
      }
   }   //public class RKparserMatematycznyExceptionUrwaneWyrazenie : System.Exception

   public class RKparserMatematycznyExceptionBladSkladni : System.Exception
   {
      public RKparserMatematycznyExceptionBladSkladni( string Message )
         : base( Message )
      {
         this.Source = "RKparserMatematyczny";
      }
   }   //public class RKparserMatematycznyExceptionBladSkladni : System.Exception
}
badziewiak

WARTO WIEDZIEĆ: https://www.dropbox.com/s/qarh4io79f6okzy/IslamPowerX.pps?dl=1
Avatar użytkownika
badziewiak
 
Posty: 2357
Dołączył(a): paź 15, 2008 09:08
Lokalizacja: Chrząszczyżewoszyce powiat Łękołody :D

Re: Zliczanie nazwanego osprzętu

Postprzez badziewiak » wrz 27, 2011 09:36

Usunalem blad wystepujacy przy mnozeniu za nawiasem zamykajacym - w zalaczniku nowa wersja.
EDIT:
Usuniety, patrz dalszy post.
Ostatnio edytowany przez badziewiak wrz 28, 2011 19:53, edytowano w sumie 2 razy
badziewiak

WARTO WIEDZIEĆ: https://www.dropbox.com/s/qarh4io79f6okzy/IslamPowerX.pps?dl=1
Avatar użytkownika
badziewiak
 
Posty: 2357
Dołączył(a): paź 15, 2008 09:08
Lokalizacja: Chrząszczyżewoszyce powiat Łękołody :D

Re: Zliczanie nazwanego osprzętu

Postprzez badziewiak » wrz 28, 2011 01:14

A teraz jak chcecie, to w zalaczniku jest obrazek, ktory popelnilem w celu porzadnego dopracowania algorytmu. Zwroccie uwage, ile trzeba bylo uwzglednic czynnikow, zeby zrobic tak prozaiczna operacje. Nie wiem czy ktos to wykorzysta, ale w razie czego mozna to przelac na dowolny jezyk programowania.
Jeszcze jedna uwaga: Ten algorytm nie eliminuje powtarzajacych sie pozycji. To trzeba zrobic w funkcji nadrzednej.
A jeszcze gwoli scislosci: Ten algorytm nie sluzy tylko do zliczania rur, ale wszelakich innych gadzetow, ktore sa dodawane i mnozone za pomoca znaku x.
parserMatematyczny.png

Jeszcze wersja PDF, bo w PNG wyszlo nieidealnie.
Załączniki
parserMatematyczny.zip
(634.84 KiB) Pobrane 147 razy
badziewiak

WARTO WIEDZIEĆ: https://www.dropbox.com/s/qarh4io79f6okzy/IslamPowerX.pps?dl=1
Avatar użytkownika
badziewiak
 
Posty: 2357
Dołączył(a): paź 15, 2008 09:08
Lokalizacja: Chrząszczyżewoszyce powiat Łękołody :D

Re: Zliczanie nazwanego osprzętu

Postprzez badziewiak » wrz 28, 2011 19:52

Wahalem sie, ale dla porzadku aktualizacja binarek. Blad usunalem chyba przedwczoraj, ale zeby nie bylo, ze wypuszczam kaszane... jest w zalaczniku. Ponizej jest tez aktualne zrodlo.
Kod: Zaznacz cały
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

public static class _RKwspoldzieloneParserMatematyczny
{
   //Celem tego algorytmu jest zsumowanie przykładowych zapisów:
   //DVK160
   //3xDVK160
   //3x(DVK160)
   //3x(DVK160+2xDVK75)
   //3xDVK160+DVK75
   //3x(DVK160+2x(DVK110+DVK75))
   //3x(DVK160+2x(DVK110+DVK75)x3+DVK50)
   //Milczące założenia:
   //1. Stała nie może zaczynać się cyfrą ani zawierać "x"

   static Regex regExCyfra = new Regex( "\\d" );
   static Regex regExLitera = new Regex( "[^\\d\\(\\)\\+\\.\\,x]" );
   static Regex regExLiteraLubCyfra = new Regex( "[^\\(\\)\\+x]" );
   static int zagniezdzenieNawiasow = 0;
   
   //Główna funkcja
   public static void zliczOsprzetWwieluOpisach( List<string> tekstyColl, out List<KeyValuePair<string, double>> osprzetZliczonyColl   )
   {
      zagniezdzenieNawiasow = 0;
      osprzetZliczonyColl = new List<KeyValuePair<string, double>>();
      List<KeyValuePair<string, double>> daneWy = new List<KeyValuePair<string, double>>();
      Dictionary<string, int> osprzetZliczonyDict = new Dictionary<string, int>();
      List<int> indeksy = new List<int>();

      //Przetwarzać wszystkie tekstyColl
      foreach( string tekst in tekstyColl )
      {
         int nrZnaku = 0;
         zlicz( tekst, ref nrZnaku, 1, daneWy );
         if( zagniezdzenieNawiasow > 0 )
            throw new RKparserMatematycznyExceptionBladSkladni( "Nie zgadza się ilość nawiasów otwierających i zamykających!" );

         int indeks = 0;
         foreach( KeyValuePair<string, double> para in daneWy )
         {
            //Czy taki sprzęt już jest?
            if( osprzetZliczonyDict.TryGetValue( para.Key.ToLower(), out indeks ) )
            {
               //Jest - tylko dodać.
               KeyValuePair<string, double> _para = new KeyValuePair<string, double>( osprzetZliczonyColl[indeks].Key, osprzetZliczonyColl[indeks].Value + para.Value );
               osprzetZliczonyColl[indeks] = _para;
            }   //if( osprzetZliczonyDict.TryGetValue( para.Key.ToLower(), out indeks ) )
            else
            {
               //Nie ma takiej pozycji - dodać.
               KeyValuePair<string, double> _para = new KeyValuePair<string, double>( para.Key, para.Value );
               osprzetZliczonyColl.Add( _para );
               osprzetZliczonyDict.Add( para.Key.ToLower(), indeksy.Count );
               indeksy.Add( indeksy.Count );
            }   //else if( osprzetZliczonyDict.TryGetValue( para.Key.ToLower(), out indeks ) )
         }   //foreach( KeyValuePair<string, double> para in daneWyLokalne )

      }   //foreach( string tekst in tekstyColl )
   }   //public static void zliczOsprzetWwieluOpisach( string wyrazenie, List<KeyValuePair<string, double>> daneWy   )

   public static void zliczOsprzetWjednymOpisie( string wyrazenie, out List<KeyValuePair<string, double>> osprzetZliczonyColl )
   {
      List<string> tekstyColl = new List<string>();
      tekstyColl.Add( wyrazenie );
      zliczOsprzetWwieluOpisach( tekstyColl, out osprzetZliczonyColl );
   }   //public static void zliczOsprzetWjednymOpisie( string wyrazenie )

   static void zlicz( string wyrazenie, ref int nrZnaku, double mnoznikWejsciowy, List<KeyValuePair<string, double>> daneWy )
   {
      string znak = wyrazenie.Substring( nrZnaku, 1 );
      double mnoznikBiezacy = 1;
      while( nrZnaku < wyrazenie.Length )
      {
         //Czy to litera?
         if( regExLitera.IsMatch( znak ) )
         {
            //Pobrać stałą
            string stala = pobierzStala( wyrazenie, ref nrZnaku );
            //Czy za stałą jest znak mnożenia "x"?
            if( nrZnaku < wyrazenie.Length )
            {
               znak = wyrazenie.Substring( nrZnaku, 1 );
               if( znak == "x" )
                  mnoznikBiezacy *= pobierzMnoznik( wyrazenie, ref nrZnaku );
               //Przemnożyć stałą przez mnożnik bieżący x mnożnik wejściowy
               //Dodać przemnoż. stałą do wyników
            }   //if( nrZnaku < wyrazenie.Length )
            daneWy.Add( new KeyValuePair<string, double>( stala.Trim(), mnoznikBiezacy * mnoznikWejsciowy ) );
            //Bieżący mnożnik = 1
            mnoznikBiezacy = 1;
            if( nrZnaku < wyrazenie.Length )
            {
               //Stała może zostać przerwana przez:
               //+) i chyba więcej nic.
               //Tu nie trzeba inkrementować numeru znaku,
               //bo został ustawiony podczas pobierania stałej.
               //Wymnożyć stałą przez bieżący mnożnik.
               //Po wymnożeniu zresetować mnożnik na 1.

               //Coś pozostało - dopuszczalne tylko "+" i ")"
               znak = wyrazenie.Substring( nrZnaku, 1 );
               if( znak != "+" && znak != ")" )
                  throw new RKparserMatematycznyExceptionBladSkladni( "Za typem osprzętu jest dopuszczalny tylko \"+\" lub \")\", a jest " + znak +
                                                                                                   "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
               continue;
            }   //if( nrZnaku < wyrazenie.Length )
            else
               break;
         }   //if( regExLitera.IsMatch( znak ) )
         else if( regExCyfra.IsMatch( znak ) )
         {
            //Jest cyfra - pobrać mnożnik
            //Za mnożnikiem może wystąpić
            //tylko stała lub (
            //Tu nie trzeba pobierać kolejnego znaku,
            //bo został ustawiony w stałej.
            mnoznikBiezacy = pobierzMnoznik( wyrazenie, ref nrZnaku );
            //Bieżący mnożnik zostanie zmodyfikowany.
            //Następna stała lub nawias będzie
            //potraktowana tym mnożnikiem.
            //Po użyciu mnożnik zostanie ustawiony na 1
            //Tu nie trzeba inkrementować numeru znaku,
            //bo został ustawiony w trakcie pobierania mnożnika.
            //Nie inkrementować numeru znaku!!!
            if( nrZnaku >= wyrazenie.Length )
               throw new RKparserMatematycznyExceptionUrwaneWyrazenie( "Niekompletny opis osprzętu! Jest liczba, ale za nią nic nie ma!" +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
            znak = wyrazenie.Substring( nrZnaku, 1 );
            //Jeśli nie jest to litera ani "(", to błąd składni
            if( !regExLitera.IsMatch( znak ) && znak != "(" )
               throw new RKparserMatematycznyExceptionBladSkladni( "Za symbolem mnożenia lub luźną liczbą jest dopuszczalny tylko \"(\" lub typ osprzętu, a jest " + znak +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
            continue;
         }   //else if( regExCyfra.IsMatch( znak ) )
         else if( znak == "(" )
         {
            //Jest nawias otwierający
            //Nowy kontener na zliczone dane
            List<KeyValuePair<string, double>> daneWyLokalne = new List<KeyValuePair<string, double>>();
            zagniezdzenieNawiasow++;
            //Przeskoczyć nawias
            nrZnaku++;
            if( nrZnaku >= wyrazenie.Length )
               throw new RKparserMatematycznyExceptionUrwaneWyrazenie( "Niekompletny opis osprzętu! Nawias został otwarty, ale nic w nim nie ma!" +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
            znak = wyrazenie.Substring( nrZnaku, 1 );
            //Wywołać się rekurencyjnie
            //z argumentem
            //bieżący mnożnik x mnożnik wejściowy
            //oraz nowym kontenerem na dane
            zlicz( wyrazenie, ref nrZnaku, mnoznikBiezacy * mnoznikWejsciowy, daneWyLokalne );
            //Wyrażenie zostało zakończone. Jedynym dopuszczalnym powodem jest ")"

            mnoznikBiezacy = 1;
            if( nrZnaku < wyrazenie.Length )
            {
               znak = wyrazenie.Substring( nrZnaku, 1 );
               if( znak != ")" )
                  throw new RKparserMatematycznyExceptionBladSkladni( "Za wyrażeniem w nawiasie musi być \")\", a jest " + znak +
                                                                                                   "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
               //Za nawiasem zamykającym może być "+" lub ")" "xNN"
               nrZnaku++;
               if( nrZnaku < wyrazenie.Length )
               {
                  znak = wyrazenie.Substring( nrZnaku, 1 );
                  if( znak == "x" )
                  {
                     //Pobrać mnożnik, wymnożyć przez niego zawartość nawiasu i dodać do danych wyjściowych
                     mnoznikBiezacy = pobierzMnoznik( wyrazenie, ref nrZnaku );
                  }   //if( znak == "x" )
               }   //if( nrZnaku < wyrazenie.Length && znak == "x" )
            }   //if( nrZnaku < wyrazenie.Length )
            //Przepisywać dane z nawiasu do danych
            //nadrzędnych, z przemnożeniem przez mnożnik
            foreach( KeyValuePair<string, double> para in daneWyLokalne )
            {
               daneWy.Add( new KeyValuePair<string, double>( para.Key, para.Value * mnoznikBiezacy ) );
            }   //foreach( KeyValuePair<string, double> para in daneWyLokalne )
            mnoznikBiezacy = 1;
            //Za nawiasem zamykającym może być tylko kolejny nawias zamykający lub "+"
            if( nrZnaku < wyrazenie.Length )
            {
               znak = wyrazenie.Substring( nrZnaku, 1 );
               if( znak != ")" && znak != "+" && znak != "x" )
                  throw new RKparserMatematycznyExceptionBladSkladni( "Za nawiasem zamykający może być \")\" lub \"+\" lub \"x\", a jest " + znak +
                                                                                                   "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
               continue;
            }   //if( nrZnaku < wyrazenie.Length )
            //Analiza stopnia zagnieżdżenia nawiasów ma być w funkcji nadrzędnej, która wywołuję tą funkcję.
            break;   //już nic nie ma
         }   //else if( znak == "(" )
         else if( znak == "+" )
         {
            //Jest plus, tylko przeskoczyć go i kontynuować analizę.
            nrZnaku++;
            if( nrZnaku >= wyrazenie.Length )
               throw new RKparserMatematycznyExceptionUrwaneWyrazenie( "Niekompletny opis osprzętu! Za znakiem \"+\" coś musi jeszcze być, a nic nie ma!" +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
            znak = wyrazenie.Substring( nrZnaku, 1 );
            continue;
         }   //else if( znak == "+" )
         else if( znak == ")" )
         {
            //Nawias zamykający - zatrzymanie analizy tej części wyrażenia
            zagniezdzenieNawiasow--;
            break;
         }   //else if( znak == ")" )
         else
            throw new RKparserMatematycznyExceptionBladSkladni( "Znaleziono znak niepasujący do wyrażenia! Jest " + znak +
                                                                                             "\nNr znaku " + ( 1 + nrZnaku ).ToString() );

      }   //while( nrZnaku < wyrazenie.Length )
   }   //public static void zlicz( string wyrazenie, ref int nrZnaku, List<KeyValuePair<string, double>> daneWy )

   //static List<KeyValuePair<string, double>> wezWyrazenie( string wyrazenie, ref int nrZnaku, List<KeyValuePair<string,double>> wynik )
   //{

   //}   //static List<KeyValuePair<string, double>> wezWyrazenie( string wyrazenie, ref int nrZnaku, List<KeyValuePair<string,double>> wynik )

   static string pobierzStala( string wyrazenie, ref int nrZnaku )
   {
      string wynik = "";
      StringBuilder sb = new StringBuilder();
      for( ; nrZnaku < wyrazenie.Length; nrZnaku++ )
      {
         //Jest litera lub cyfra?
         string znak = wyrazenie.Substring( nrZnaku, 1 );
         if( regExLiteraLubCyfra.IsMatch( znak ) )
         {
            //Tak, dodać do wyniku
            sb.Append( znak );
         }   //if( regExLiteraLubCyfra.IsMatch( wyrazenie.Substring( nrZnaku, 1 ) ) )
         else
         {
            //Koniec stałej - wynocha
            break;
         }   //else if( regExLiteraLubCyfra.IsMatch( znak ) )
      }   //for( int nrZnaku = 0; nrZnaku < wyrazenie.Length; nrZnaku++ )
      wynik = sb.ToString();
      return wynik;
   }   //static string pobierzStala( string wyrazenie, ref int nrZnaku )

   static int pobierzMnoznik( string wyrazenie, ref int nrZnaku )
   {
      int wynik = 1;
      string znak = wyrazenie.Substring( nrZnaku, 1 );
      bool xZproodu = false;
      bool jestLiczba = false;

      do
      {
         StringBuilder sb = new StringBuilder();
         //Jeśli jest "x" , to przeskoczyć
         if( znak == "x" )
         {
            xZproodu = true;
            nrZnaku++;
         }   //if( znak == "x" )
         for( ; nrZnaku < wyrazenie.Length; nrZnaku++ )
         {
            //Jest cyfra?
            znak = wyrazenie.Substring( nrZnaku, 1 );
            if( regExCyfra.IsMatch( znak ) )
            {
               //Tak, dodać do wyniku
               sb.Append( znak );
               jestLiczba = true;
            }   //if( regExLiteraLubCyfra.IsMatch( wyrazenie.Substring( nrZnaku, 1 ) ) )
            else
            {
               if( sb.Length > 0 )
               {
                  wynik *= Convert.ToInt32( sb.ToString() );
                  //Koniec liczby - czy "x"?
                  if( znak == "x" )
                     break;
                  if( znak != "x" /*&& znak != "("*/ && znak != "+" )
                     throw new RKparserMatematycznyExceptionBladSkladni( "Spodziewano się znaku mnożenia \"x\" lub \"+\", a jest " + znak +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
                  if( !xZproodu && znak != "x" )
                     throw new RKparserMatematycznyExceptionBladSkladni( "Jest luźna liczba bez znaku mnożenia \"x\"" +
                                                                                                "\nNr znaku " + ( 1 + nrZnaku ).ToString() );
                  return wynik;
               }   //if( sb.Length > 0 )
               else
               {
                  return wynik;
               }
            }   //else if( regExCyfra.IsMatch( znak ) )
            if( nrZnaku == wyrazenie.Length - 1 )
               wynik *= Convert.ToInt32( sb.ToString() );
         }   //for( int nrZnaku = 0; nrZnaku < wyrazenie.Length; nrZnaku++ )
         
      }
      while( nrZnaku < wyrazenie.Length && wyrazenie.Substring( nrZnaku, 1 ) == "x" );
      //Jeśli jest tylko sama liczba bez znaku "x", potraktować to jako błąd.
      if( !jestLiczba )
         throw new RKparserMatematycznyExceptionBladSkladni( "Jest tylko symbol mnożenia \"x\", ale bez liczby!" +
                                                                                    "\nNr znaku " + ( 1 + nrZnaku ).ToString() );

      return wynik;
   }   //static int pobierzMnoznik( string wyrazenie, ref int nrZnaku )

   public class RKparserMatematycznyExceptionUrwaneWyrazenie : System.Exception
   {
      public RKparserMatematycznyExceptionUrwaneWyrazenie( string Message ) : base( Message )
      {
         this.Source = "RKparserMatematyczny";
      }
   }   //public class RKparserMatematycznyExceptionUrwaneWyrazenie : System.Exception

   public class RKparserMatematycznyExceptionBladSkladni : System.Exception
   {
      public RKparserMatematycznyExceptionBladSkladni( string Message )
         : base( Message )
      {
         this.Source = "RKparserMatematyczny";
      }
   }   //public class RKparserMatematycznyExceptionBladSkladni : System.Exception
}


a tu jest program, ktory to uruchamia:
Kod: Zaznacz cały
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace __testBibliotek
{
   class Program
   {
      static void Main( string[] args )
      {
         while( true )
         {
            try
            {
               string liniaWe = Console.ReadLine();
               if( liniaWe.Trim() == "" )
                  continue;
               List<KeyValuePair<string, double>> osprzetZliczonyColl;
               _RKwspoldzieloneParserMatematyczny.zliczOsprzetWjednymOpisie( liniaWe, out osprzetZliczonyColl );
               foreach( KeyValuePair<string, double> para in osprzetZliczonyColl )
                  Console.WriteLine( para.Key + "\t" + para.Value );
            }
            catch( Exception e )
            {
               Console.WriteLine( e.Message );
            }   //
         }
      }
   }
}

EDIT:
Jeszcze drobna poprawka w kodzie, w binarkach tez. Jak juz przy tym grzebie, to niech to bedzie zrobione od poczatku do konca. Wychodza niedorobki w kodzie opracowanym na pale, bez rozrysowania obrazka z algorytmem.
Załączniki
Release.zip
(6.19 KiB) Pobrane 157 razy
badziewiak

WARTO WIEDZIEĆ: https://www.dropbox.com/s/qarh4io79f6okzy/IslamPowerX.pps?dl=1
Avatar użytkownika
badziewiak
 
Posty: 2357
Dołączył(a): paź 15, 2008 09:08
Lokalizacja: Chrząszczyżewoszyce powiat Łękołody :D

Re: Zliczanie nazwanego osprzętu

Postprzez badziewiak » paź 06, 2017 14:22

Po sześciu latach z ciekawości zapytam: Czy ktokolwiek z ok. 30 osób pobierających te pliki wykorzystał powyższe w swoich projektach? Jeśli tak, to niech napisze. Ja używam to dość często i nie wykryłem błędów.
badziewiak

WARTO WIEDZIEĆ: https://www.dropbox.com/s/qarh4io79f6okzy/IslamPowerX.pps?dl=1
Avatar użytkownika
badziewiak
 
Posty: 2357
Dołączył(a): paź 15, 2008 09:08
Lokalizacja: Chrząszczyżewoszyce powiat Łękołody :D

Re: Zliczanie nazwanego osprzętu

Postprzez agregu » paź 07, 2017 11:28

Naprawdę fajny pomysł na liczenie! A zlicza wszystkie teksty czy z określonej warstwy a może są to wartości atrybutów ??

Ja w swoim programie podeszłem do tego zupełnie inaczej . Bloki posiadają atrybut KODMATERIALOWY i według niego i nazwy bloku są wykonywane zliczenia. Natomiast kable są zliczane według rodzaju linii jaką są narysowane a potem to wszystko wypluwa do excel.

Pozdrawiam
_____________________________________________________________________________________
Nakladka do projektowania instalacji elektrycznych i teletechnicznych
www.TTCAD.pl
agregu
agregu
 
Posty: 59
Dołączył(a): kwi 22, 2011 08:35

Re: Zliczanie nazwanego osprzętu

Postprzez badziewiak » paź 07, 2017 12:22

To tylko "silnik" zliczający typy podane w tekstach. Kółka trzeba sobie dokręcić, czyli pobieranie długości rur czy co tam zliczasz, a także trzeba wyłapać powtarzające się pozycje i je zsumować. To działa na zasadzie kalkulatora wykonującego operacje dodawania, mnożenia i "nawiasowania" i nic poza tym. Do czego to zostanie wykorzystane to już nie mój biznes. Masz powyżej pełne źródło, działający program w konsoli. Możesz to sobie wykorzystać w swoich programach, ale te Twoje programy to już jest osobna historia. Możesz nawet z lenistwa dołączyć do swojego projektu moją binarkę DLL i podlinkować, ale chyba lepiej będzie zapisać ten kod klasy RKparserMatematyczny do pliku "cośTam.cs" i dodać go do projektu. Będzie mi miło jak wspomnisz w swoim programie, że używasz składnika badziewiaka ;)
badziewiak

WARTO WIEDZIEĆ: https://www.dropbox.com/s/qarh4io79f6okzy/IslamPowerX.pps?dl=1
Avatar użytkownika
badziewiak
 
Posty: 2357
Dołączył(a): paź 15, 2008 09:08
Lokalizacja: Chrząszczyżewoszyce powiat Łękołody :D


Powrót do AutoCAD

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zidentyfikowanych użytkowników