CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Manipulacja tekstem w komponencie Memo
Strona 1 z 1

Manipulacja tekstem w komponencie Memo

Nowy postNapisane: czwartek, 26 grudnia 2019, 17:59
przez lukagrom
Kwestia jest następująca. Są dwa pliki w katalogu instalacyjnym Embarcadero (o dość długiej ścieżce), które sobie otworzę, zapiszę jako zmienne tekstowe, a następnie owe zmienne połączę (skopiuje do siebie lub zsumuje) w jedną zmienną, po czym jeśli się uda zapiszę to jako strona/plik .html i może gdzieś to wyślę.
Pliki i lokalizacja:
KOD cpp:     UKRYJ  
char *path_Before="C:\\Program Files\\Embarcadero\\Studio\\18.0\\Path-Before-Install.txt";
char *path_After="C:\\Program Files\\Embarcadero\\Studio\\18.0\\Path-After-Install.txt";
 

Kłania się biblioteka fstream do otwierania plików, ale z racji tego, że średnio mi poszło jej użycie (krzaki i komunikaty o braku dostępu), poszedłem na łatwiznę i kulturalnie otwarłem to komponentami Memo.
KOD cpp:     UKRYJ  
Memo1->Lines->LoadFromFile(path_Before);
Memo2->Lines->LoadFromFile(path_After);
 

Otwarło się znakomicie, na 2 memo kilkulinijkowy obszar z tekstami.
Pozostało przypisać to do zmiennych tekstowych. Zdecydowałem się na dynamiczne AnsiString gdzie rozmiar wytyczy ilość linijek w Memo.
KOD cpp:     UKRYJ  
 int count_Memo1,count_Memo2;
 count_Memo1=Memo1->Lines->Count;
 count_Memo2=Memo2->Lines->Count;
 AnsiString *buff_Before;
 AnsiString *buff_After;
 AnsiString *sum_Result;
 buff_Before=new AnsiString[count_Memo1];
 buff_After=new AnsiString[count_Memo2];
 sum_Result=new AnsiString[count_Memo1+count_Memo2];
 

Teraz proste przypisanie linijek Memo do tablic tekstowych:
KOD cpp:     UKRYJ  
for(i=0;i<count_Memo1;i++)
 {
  buff_Before[i]=Memo1->Lines->Strings[i];
 }
 for(i=0;i<count_Memo2;i++)
 {
  buff_After[i]=Memo2->Lines->Strings[i];
 }
 for(i=0;i<count_Memo1;i++)
  sum_Result[i]=buff_Before[i];
 for(i=0;i<count_Memo2;i++)
  sum_Result[count_Memo1+i]=buff_After[i];
 

I chyba nie takie proste do końca, bo dołączając 3 Memo by uzyskać sumę z tekstów:
KOD cpp:     UKRYJ  
for(i=0;i<count_Memo1+count_Memo2;i++)
 {
  Memo3->Lines->Strings[i]=sum_Result[i];
 }
 

Pokazuje mi raptem 2 linijki z Memo1.
Na wszelki wypadek sprawdziłem wartości liczbowe z ilości linijek, które są jednocześnie wielkościami tablica zmiennych AnsiString.
KOD cpp:     UKRYJ  
 int count_Memo3=Memo3->Lines->Count;
 Edit1->Text=IntToStr(count_Memo1);
 Edit2->Text=IntToStr(count_Memo2);
 Edit3->Text=IntToStr(count_Memo3);
 

I wszystko się zgadza, mają dokładnie tyle jaka jest liczba liniek w wyświetlanych komponentach Memo.
Wszystko wskazuje, że te przepisania są chyba błędne:
KOD cpp:     UKRYJ  
 for(i=0;i<count_Memo1;i++)
 {
  buff_Before[i]=Memo1->Lines->Strings[i];
 }
 for(i=0;i<count_Memo2;i++)
 {
  buff_After[i]=Memo2->Lines->Strings[i];
 }
 

Ma ktoś jakiś pomysł co tu może być zle? Na kompilatorze nie ma nawet warningów

Oczywiście usunięcie dynamicznych też się odbyło:
KOD cpp:     UKRYJ  
delete sum_Result;
delete buff_After;
delete buff_Before;

 


Spróbowałem jeszcze czegoś takiego:
KOD cpp:     UKRYJ  
for(i=0;i<count_Memo2;i++)
 {
  Memo3->Lines->Strings[i]=buff_After[i];
 }
 

I ponownie tylko 2 linijki z zakładanych 12;
OK. Więc jest już 100% pewność, że:
KOD cpp:     UKRYJ  
buff_Before=new AnsiString[count_Memo1];
 buff_After=new AnsiString[count_Memo2];
 sum_Result=new AnsiString[count_Memo1+count_Memo2];
 for(i=0;i<count_Memo1;i++)
 {
  buff_Before[i]=Memo1->Lines->Strings[i];
 }
 for(i=0;i<count_Memo2;i++)
 {
  buff_After[i]=Memo2->Lines->Strings[i];
 }
 

takie przypisanie, mimo, że tolerowane przez kompilator, jednak ma jakiś inny, dziwaczny rezultat.
Podejrzewam, że kłóci się tablica AnsiStringów z przypisaniem Memo->Lines->Strings[ile_tam];

Re: Manipulacja tekstem w komponencie Memo

Nowy postNapisane: piątek, 27 grudnia 2019, 11:53
przez polymorphism
Nie tak powinno być:
KOD cpp:     UKRYJ  
for (int i = 0; i < count_Memo1 + count_Memo2; i++) {
    Memo3->Lines->Add(sum_Result[i]);
}

?

Oczywiście usunięcie dynamicznych też się odbyło:

Z błędem. Tablice powinieneś usuwać wyrażeniem delete[].

Pr0tip: std::vector zamiast tablic dynamicznych.

Re: Manipulacja tekstem w komponencie Memo

Nowy postNapisane: sobota, 28 grudnia 2019, 11:28
przez lukagrom
Danke, rzeczywiście Items->Add() daje ten właściwy i oczekiwany wynik, przy czym Memo wymaga przed użyciem wyczyszczenia: Memo3->Clear()
Całość zapiszę w formacie HTML, choć nie wiem czy tak w ogóle można z poziomu Buildera robić.
KOD cpp:     UKRYJ  
 int sum_Count=count_Memo1+count_Memo2;
 AnsiString begin_Page[6]={"<HTML>","<HEAD>","<TITLE>","</TITLE","</HEAD>","<BODY>"};
 AnsiString end_Page[2]={"</BODY>","</HTML>"};
 int size_html_Page=sum_Count+6+2;
 AnsiString *page_HTML=new AnsiString[size_html_Page];
 for(i=0;i<6;i++)
 {
  page_HTML[i]=begin_Page[i];
 }
 for(i=0,j=6;i<sum_Count;i++,j++)
 {
  page_HTML[j]=sum_Result[i]+" <br> ";
 }
 for(i=0,j=6+sum_Count;i<2;i++,j++)
 {
  page_HTML[j]=end_Page[i];
 }
 

Wypadało by zobaczyć wynik:
KOD cpp:     UKRYJ  
 for(i=0;i<size_html_Page;i++)
  Memo4->Lines->Add(page_HTML[i]);
 

Wygląda poprawnie, jak najbardziej prymitywna strona bez opisów znaczników w HTML. Teraz zapis do pliku i uruchomienie w domyślnej przeglądarce.
KOD cpp:     UKRYJ  
AnsiString www="paths_Embarcadero.html";
 Memo4->Lines->SaveToFile(www);
 AnsiString application_Path=ExtractFileDir(Application->ExeName);
 AnsiString execute_Path="file://"+application_Path+"\\"+www;
 ShellExecute(Handle,"open",execute_Path.c_str(),"",".",SW_NORMAL);
 delete [] page_HTML;
 

Re: Manipulacja tekstem w komponencie Memo

Nowy postNapisane: sobota, 28 grudnia 2019, 14:08
przez polymorphism
Po co ten new i tablice, skoro to samo możesz zrobić wykorzystując np. std::ostringstream?
KOD cpp:     UKRYJ  
const char* pageHeader = "<HTML><HEAD><TITLE></TITLE></HEAD><BODY>";
const char* pageFooter = "</BODY></HTML>";

std::ostringstream oss;

oss << pageHeader << '\n';

for (int i = 0; i < sum_Count;i++) {
        oss << sum_Result[i].c_str() << " <br> " << '\n';
}

oss << pageFooter;

Kod prosty i bezpieczny. Choć jeśli ta strona ma być zapisana od razu do pliku, to zamiast std::ostringstream lepiej użyć std::ofstream.

Gdybyś zamiast sum_Result i sum_Count dał dał prawilnie std::vector, to pętla byłaby jeszcze prostsza:
KOD cpp:     UKRYJ  
for (auto& v : sum_Result) {
        oss << v.c_str() << " <br> " << '\n';
}

Re: Manipulacja tekstem w komponencie Memo

Nowy postNapisane: sobota, 28 grudnia 2019, 15:36
przez lukagrom
Na pewno szybsze i elegantsze. Tyle, że to już mnóstwo nowych definicji, klas, bibliotek do poznania, bardziej dla kogoś, kto chce być na bieżąco z aktualnymi zmianami,softem, sprzętem ciągle ewoluującego C++. Pewnie to efektywniejsze, aktualniejsze etc, ale na moje skromne, amatorskie potrzeby wystarcza mi ten archaiczny zapis, niewiele różniący się od C. Jeszcze mam podręczniki z Olimpiad w C++, gdzie wyniki zapisywano do plików w fprintf, a i malloc(), też był akceptowalny przez "audytorium" przy deklaracji tablic. Dzięki temu ten język jest "lajtowy" dla amatorów i pozwala hobbystycznie rzezbic jakieś skromne zagadnienia. Gdyby był jakiś wymóg ciągłej samodyscypliny w stosowaniu aktualnych nowości, połowa ludzi zarzuciła by te hobby zostawiając pisanie tylko profesjonalistom a i C++ Builder padł by śmiercią naturalną, bo z ciekawostek nadal najwięcej użytkowników ciągle używa C++ Builder 6. Nawet ktoś w USA ciągle gry arkadowe w tym pisze o ośrodkach akademickich nie wspominając, które do dzisiaj używają ten stary pakiet jako narzędzie obliczeniowe.

Re: Manipulacja tekstem w komponencie Memo

Nowy postNapisane: sobota, 28 grudnia 2019, 16:35
przez polymorphism
Używają C++ Buildera 6, bo jest darmowy. Problem w tym, że jest koszmarnie przestarzały i przez to mało wartościowy dzisiaj. Doprecyzujmy, że to "najwięcej użytkowników" dotyczy użytkowników C++ Buildera, bo na pewno nie ogółu piszących w C++ (tu rządzi Visual C++/Qt Creator/inne IDE dla gcc).

Co do Twojego podejścia: kompletnie go nie rozumiem. Skoro używasz jakiegoś narzędzia, a C++ jest takim narzędziem, to naturalną potrzebą jest zdobywanie technik/umiejętności, które usprawnią posługiwanie się tym narzędziem. Takich rzeczy uczy się w praktyce. Nie trzeba być profesjonalistą, by takie umiejętności posiąść.

Nawet ktoś w USA ciągle gry arkadowe w tym pisze o ośrodkach akademickich nie wspominając, które do dzisiaj używają ten stary pakiet jako narzędzie obliczeniowe.

Podejrzewam, że ze względu na legacy code niż to, że to takie wciąż-na-czasie-środowisko.

Re: Manipulacja tekstem w komponencie Memo

Nowy postNapisane: sobota, 28 grudnia 2019, 16:37
przez lukagrom
Tu jeszcze (robiona starym sposobem) na szybko funkcja zapisująca z pliku tekstowego do html.
KOD cpp:     UKRYJ  
#define max_Size 256
void Save_to_HTML(char *text_File, char *new_html_File)
{

    int i,j,line=0;
    fstream file_Text;
    string buff[max_Size];
    file_Text.open(text_File,ios::in);
    while(!file_Text.eof())
    {
        getline(file_Text,buff[line]);
        ++line;
    }
    file_Text.close();
    int sum_Count=line;
    string begin_Page[6]={"<HTML>","<HEAD>","<TITLE>","</TITLE","</HEAD>","<BODY>"};
    string end_Page[2]={"</BODY>","</HTML>"};
    int size_html_Page=sum_Count+6+2;
    string *page_HTML=new string[size_html_Page];
    for(i=0;i<6;i++)
   {
    page_HTML[i]=begin_Page[i];
   }
   for(i=0,j=6;i<sum_Count;i++,j++)
   {
    page_HTML[j]=buff[i]+" <br> ";
   }
   for(i=0,j=6+sum_Count;i<2;i++,j++)
   {
    page_HTML[j]=end_Page[i];
   }
   fstream file_HTML;
   file_HTML.open(new_html_File, ios::out | ios::app);
   if(file_HTML.good() == true)
   {
       for(i=0;i<size_html_Page;i++)
       {
           file_HTML<<page_HTML[i]<<"\n";
       }
       file_HTML.close();
   }
   delete [] page_HTML;

}
 

Re: Manipulacja tekstem w komponencie Memo

Nowy postNapisane: sobota, 28 grudnia 2019, 20:07
przez polymorphism
Można prościej, bez ograniczeń i niebezpiecznych konstrukcji:
KOD cpp:     UKRYJ  
void Save_to_HTML(const char* text_File, const char* new_html_File)
{
        const char* pageHeader = "<HTML><HEAD><TITLE></TITLE></HEAD><BODY>";
        const char* pageFooter = "</BODY></HTML>";

        std::string line;
        std::ifstream textFile(text_File);

        if (textFile.is_open()) {
                std::ofstream htmlFile(new_html_File);
               
                htmlFile << pageHeader << '\n';

                while (std::getline(textFile, line)) {
                        htmlFile << line << " <br> ";
                }

                htmlFile << pageFooter;
        }
}

Re: Manipulacja tekstem w komponencie Memo

Nowy postNapisane: sobota, 28 grudnia 2019, 20:42
przez lukagrom
Jakieś 60% objętości oszczędności kodu, z pamięcią pewnie jeszcze większy zysk. Jak nowy Mercedes do malucha.Zwłaszcza, że z każdym rokiem dochodzi jakaś nowa specyfikacja/modyfikacja języka. Coś nawet czytałem, że ostatnia podebrała sporo mechanizmów z javy i kto chce zostać w obiegu musi już programować zdarzenia z uwzględnieniem świata vector-ów, std-ów, sstream-ów i innych podobnych. Oczywista oczywistość. Na pocieszenie dinozaurom pozostaje tylko fakt, że próby przerobienia w Linuksach kodu żródłowego z C do C++ skończyły się niepowodzeniem.

Re: Manipulacja tekstem w komponencie Memo

Nowy postNapisane: sobota, 28 grudnia 2019, 21:18
przez polymorphism
Zwłaszcza, że z każdym rokiem dochodzi jakaś nowa specyfikacja/modyfikacja języka.

Bez przesady. Aktualny standard to C++17, czyli praktycznie sprzed trzech lat. Nowy planowany jest na 2020. To nie jest też tak, że każdy nowy standard wywraca poprzednie. Ewolucja, nie rewolucja. Dodano nowe konstrukcje językowe, ale też bez szaleństw. Sporo rzeczy dodano do biblioteki standardowej, która była uboga w stosunku do bibliotek innych współczesnych języków.

Coś nawet czytałem, że ostatnia podebrała sporo mechanizmów z javy

Eee, raczej nie. Póki co garbage collectora nie ma ;)

kto chce zostać w obiegu musi już programować zdarzenia z uwzględnieniem świata vector-ów, str-ów, sstream-ów i innych podobnych.

Przecież wektory, stringi czy strumienie są tak stare jak C++. To żadne nowości! Trzeba ich po prostu używać, zamiast babrać się w C z klasami.

Na pocieszenie dinozaurom pozostaje tylko fakt, że próby przerobienia w Linuksach kodu źródłowego z C do C++ skończyły się niepowodzeniem.

A wiesz, że kernel Linuksa wraz z modułami to miliony linii kodu? Takich ogromnych projektów nie przepisuje się na inny język ot tak. Dodatkowo kernel Linuksa jest przeznaczony na różne platformy sprzętowe,gdzie po prostu może nie być dobrego kompilatora C++ (choć nie wiem, czy dziś to jest jeszcze aktualne; gdzieś czytałem, że C++ zaczyna powoli wypierać C w dziedzinie programowania na mikrokontrolery).