CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

[BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

dział ogólny

[BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez areq47 » czwartek, 2 czerwca 2011, 13:08

Witam,
piszę program odbierający maile i sprawdzający czy nie są spamem.
Treść maila pobieram do Memo. Aby filtr antyspamowy działał, muszę każde słowo z maila zapisać do bazy danych. Z treści emaila muszę usunąć wszystkie znaczniki html (nie są potrzebne). Napisałem kod usuwający pojedynczy znacznik html po kliknięciu buttona:

KOD cpp:     UKRYJ  
WiadomoscMemo->Text=WiadomoscMemo->Text.SubString(0,WiadomoscMemo->Text.Pos(<")-1)+WiadomoscMemo->Text.SubString(WiadomoscMemo->Text.Pos(">")+1,WiadomoscMemo->Text.Length());


Usuwa on pierwszy napotkany znacznik. Jak napisać pętlę, która automatycznie usunie wszystkie znaczniki z memo??
Próbowałem czegoś takiego, ale program nie może wyjść z takiej pętli:
KOD cpp:     UKRYJ  
while(WiadomoscMemo->Text.Pos("<")!=-1){
WiadomoscMemo->Text=WiadomoscMemo->Text.SubString(0,WiadomoscMemo->Text.Pos(<")-1)+WiadomoscMemo->Text.SubString(WiadomoscMemo->Text.Pos(">")+1,WiadomoscMemo->Text.Length());
}
Avatar użytkownika
areq47
Bladawiec
Bladawiec
 
Posty: 8
Dołączył(a): czwartek, 7 kwietnia 2011, 15:59
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: Windows 7 64bit
Kompilator: Builder 6
Gadu Gadu: 668046
    Windows 7Firefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez Cyfrowy Baron » piątek, 3 czerwca 2011, 09:24

Nie ma na to gotowych rozwiązań, a i pętla się nie sprawdzi, gdyż musiałbyś wyłapywać wszelkie możliwe znaczniki html. Powinieneś skorzystać z wyrażeń regularnych, ale to wymaga poduczenia się o tym. Korzystasz ze środowiska Borland C++Builder 6, więc nie wiem, czy masz tam jakieś biblioteki do obsługi tych wyrażeń. Jakieś biblioteki BOOST, wymagana jest regex.hpp.

Temat wyrażeń regularnych poruszany był w wątku: Regular Expressions

Wyrażenia regularne pozwalają nie tyle na usuwanie tagów html, ile na wydobywanie tekstu spośród tych tagów, co jest idealne dla Twoich potrzeb.

W załączniku masz materiały pomocnicze dla regex.
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4731
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 445
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez Darek_C++ » sobota, 4 czerwca 2011, 10:38

Jakiś dziwny to filtr który aby działał musi zapisywać dane do bazy. Znaczniki HTML możesz usuwać stosując funkcję:
KOD cpp:     UKRYJ  
String out = StringReplace(temp, "<h1>", "",TReplaceFlags() << rfReplaceAll);
out = StringReplace(out , "</h1>", "",TReplaceFlags() << rfReplaceAll);

itd... dla wszystkich par. Możesz też użyć wyrażeń regularnych z boost::regex_replace do podmieniania znaczników według odpowiedniego wzorca np dla nagłówków <h1>, <h2>, definicji wstawiającej link <a href=""></a>, <img src="" /> itd...

Napisanie filtra antyspamowego jest zadaniem niezwykle trudnym, do zastosowań "amatorskich" możesz sprawdzać wiadomość pod kątem zaufanego emaila nadawcy lub serwera SMTP nadawcy, występowania chociaż jednego polskiego znaku typu ą,ę,ś,ć chyba, że obsługujesz też wiadomości obcojęzyczne jako "nie spam".
Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez Cyfrowy Baron » sobota, 4 czerwca 2011, 11:56

W zasadzie do sprawdzania, czy tekst nie zawiera testu będące spamem nie trzeba wcale usuwać żadnych tagów HTML, wystarczy sprawdzić czy w tekście występuje wyraz lub wyrażenie oznaczone jako spam, np:

KOD cpp:     UKRYJ  
Strong spam = "tekst spam";
String text = Memo1->Text;

int x = text.AnsiPos(spam);

if(x > 0) ShowMessage("Wiadomość zawiera spam");
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4731
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 445
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez Darek_C++ » sobota, 4 czerwca 2011, 12:21

Możesz zdefiniować sobie funkcję lub metodę kalsy zawierającej w ciele kod który wczyta z pliku słowa które zdefiniowałeś jako spam i w pętli przeszuka telst wejściowy od kątem ich występowania i wywołanie zwracające - TRUE = ShowMessage("Wiadomość zawiera spam"); return; klasyfikuje mail do spamu.
Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez areq47 » niedziela, 5 czerwca 2011, 00:40

Darek_C++ napisał(a):Jakiś dziwny to filtr który aby działał musi zapisywać dane do bazy. Znaczniki HTML możesz usuwać stosując funkcję:
KOD cpp:     UKRYJ  
String out = StringReplace(temp, "<h1>", "",TReplaceFlags() << rfReplaceAll);
out = StringReplace(out , "</h1>", "",TReplaceFlags() << rfReplaceAll);

itd... dla wszystkich par. Możesz też użyć wyrażeń regularnych z boost::regex_replace do podmieniania znaczników według odpowiedniego wzorca np dla nagłówków <h1>, <h2>, definicji wstawiającej link <a href=""></a>, <img src="" /> itd...

Napisanie filtra antyspamowego jest zadaniem niezwykle trudnym, do zastosowań "amatorskich" możesz sprawdzać wiadomość pod kątem zaufanego emaila nadawcy lub serwera SMTP nadawcy, występowania chociaż jednego polskiego znaku typu ą,ę,ś,ć chyba, że obsługujesz też wiadomości obcojęzyczne jako "nie spam".


To jest program do pracy magisterskiej ;) Filtruje spam za pomocą wnioskowania Bayesa. Każde słowo z maila musi odczytać i jeśli go nie ma w bazie to je dodać. Każde poszczególne słowo ma przypisane prawdopodobieństwo występowania w wiadomości spamowej. Jeśli słowa nie było w bazie to dajemy wartość neutralną ( 0,4 ). Kiedy już odczytamy wszystkie słowa liczymy dla nich prawdopodobieństwo warunkowe tego że są spamem. Jeśli prawdopodobieństwo jest powyżej jakieś ustalonej wartości mówimy że to spam. Na początku użytkownik sam określa przy wiadomościach czy jest ona spamowa (uznanie takiej wiadomości za spam powiększa prawdopodobieństwa dla wszystkich słów występujących w mailu o jakiś stopień).

Dlatego też muszę najpierw z tekstu wiadomości usunąć znaczniki html i odczytać każde słowo występujące w mailu ;) Naprawdę nie ma możliwości napisania jakiegoś warunku do pętli while przedstawionej w moim pierwszym poście? Bez pętli usuwa pierwszy napotkany znacznik. Problem mam tylko z tym warunkiem, bo nie chce mi z pętli wyjść ;)
Avatar użytkownika
areq47
Bladawiec
Bladawiec
 
Posty: 8
Dołączył(a): czwartek, 7 kwietnia 2011, 15:59
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: Windows 7 64bit
Kompilator: Builder 6
Gadu Gadu: 668046
    Windows 7Firefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez Cyfrowy Baron » niedziela, 5 czerwca 2011, 09:19

Można to załatwić takim kodem:

KOD cpp:     UKRYJ  
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 String text = Memo1->Text;
 bool process = true;

 do
 {
  int p1 = text.Pos("<");
  int p2 = text.Pos(">");

  if(p1 > 0 && p2 > 0)
  {
   text = text.Delete(p1, p2 - p1 + 1);
   process = true;
  }
  else process = false;
 }
 while(process);

 Memo1->Text = text;
}


Jednak to zadziała prawidłowo, tylko w sytuacji, gdy użytkownik nie użyje w treści wiadomości znaków < i >, czyli to się sprawdza dla wiadomości w formacie html, gdyż tam te znaki są reprezentowane przez &lt; i &gt; Nie zadziała jednak dla wiadomości tekstowych.
Kod jest niewydajny i w przypadku dużych wiadomości może się nie sprawdzić.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4731
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 445
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez polymorphism » niedziela, 5 czerwca 2011, 11:00

Dodam tylko, że za każdym > dodałbym spację, bo może dojść do sytuacji, że dwa wyrazy zbiją się w jeden, a to może nieco utrudnić analizę.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2263
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 210
System operacyjny: Windows 8.1
Windows 10
Linux Mint 19
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez Cyfrowy Baron » niedziela, 5 czerwca 2011, 11:03

polymorphism napisał(a):Dodam tylko, że za każdym > dodałbym spację


Ale przecież w źródle wiadomości po znaku > wcale nie musi występować spacja i wtedy pętla zakończy działanie, np:

KOD text:     UKRYJ  
<b>treść wiadomości</b>


jeżeli dam spację, czyli

KOD cpp:     UKRYJ  
int p2 = text.Pos("> ");


to nie wyeliminuje mi tego tagu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4731
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 445
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez polymorphism » niedziela, 5 czerwca 2011, 11:09

Ale mi nie chodzi o dodanie spacji we wzorcu, tylko o dodanie spacji w zamian za usunięty tag. Żeby np. dla takiego przypadku:

    Lorem ipsum dolor sit amet</br>consectetuer adipiscing elit
nie dochodziło do:

    Lorem ipsum dolor sit ametconsectetuer adipiscing elit
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2263
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 210
System operacyjny: Windows 8.1
Windows 10
Linux Mint 19
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez Cyfrowy Baron » niedziela, 5 czerwca 2011, 11:13

Ups! Już wiem o co Tobie chodzi! Próbowałem to zrobić, ale niestety tekst się trochę sypie.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4731
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 445
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez polymorphism » niedziela, 5 czerwca 2011, 11:28

Coś w ten deseń:
KOD cpp:     UKRYJ  
String text1 = Memo1->Text;
String text2;

bool tag = false;
 
for(int i = 1; i <= text1.Length(); ++i)
{
        if(tag)
        {
                if(text1[i] == '>') { tag = false; text2 += ' '; }
                continue;
        }
       
        if(text1[i] == '<') { tag = true; continue; }
        text2 += text1[i];
}
 
C++ Reference - opis wszystkich klas STL-a i funkcji C.

Za ten post autor polymorphism otrzymał podziękowanie od:
areq47
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2263
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 210
System operacyjny: Windows 8.1
Windows 10
Linux Mint 19
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez Cyfrowy Baron » niedziela, 5 czerwca 2011, 11:49

Tak to działa, ale Twoja pętla działa przez czas: text1.Length(), czyli analizuje każdy znak w tekście, podczas gdy moja działa tylko tak długo jak długo występują tagi.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4731
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 445
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez polymorphism » niedziela, 5 czerwca 2011, 12:14

... i co każde usunięcie taga przeszukuje od nowa tekst. Trochę nie rozumiem zarzutu, przecież Twój kod też musi analizować każdy znak, tyle że robi to w sposób niejawny, wewnątrz metody Pos. Robi to wielokrotnie, do momentu usunięcia wszystkich tagów. U mnie wszystko odbywa się w jednym przebiegu pętli, zatem jest to optymalniejsze rozwiązanie.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2263
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 210
System operacyjny: Windows 8.1
Windows 10
Linux Mint 19
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB6] Jak napisać pętlę usuwającą znaczniki z memo?

Nowy postprzez Darek_C++ » niedziela, 5 czerwca 2011, 12:54

areq47 napisał(a):Dlatego też muszę najpierw z tekstu wiadomości usunąć znaczniki html i odczytać każde słowo występujące w mailu
Nie ma takiej potrzeby, bo za pomocą wyrażeń regularnych możesz odzielić ciąg znaków pasujących do "słów" od znaczników HTML które mają określoną budowę. Nie rozumiem też dlaczego koniecznie musi się to odbyć przy pętli do usuwania skoro można to zrobić bez wykorzystania pętli.

Zapoznaj się z kodem funkcji http://php.net/manual/en/function.strip-tags.php z PHP dostępnym w kodzie źródłowym PHP. Funkcja ta "czyści" tekst z znaczników HTML.
Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Następna strona

  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 9 gości

cron