Zeichen aus einem String entfernen [ERLEDIGT]

Alle Fragen um die Programmierung, die sich sonst nicht kategorisieren lassen. Von Makro bis Codeblock, von IF bis ENDIF

Moderator: Moderatoren

Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Zeichen aus einem String entfernen [ERLEDIGT]

Beitrag von Manfred »

Moin,

hier mal wieder eine Frage an die Tempo Profis

Ist diese Lösung hier eher schnell, oder eher langsam und umständlich?

Code: Alles auswählen

PROCEDURE main()
          LOCAL string

          cls
          use \videoneudaten\datenbanken\vo\titel new
          copy structure TO titeltest
          use titeltest new
          DO WHILE ! titel->(eof())
             IF titel->(Recno()) %500 == 0
                @ 5,1 say titel->(recno())
             ENDIF
             string := titel->bez
             entfernen(@string)
             titeltest->(Dbappend())
             titeltest->id  := titel->id
             titeltest->bez := string
             titel->(Dbskip())
          ENDDO
          RETURN
********************************************************************************
FUNCTION entfernen(string)
         LOCAL altelaenge  := maxline(string)
         LOCAL neuelaenge  := 0
         LOCAL neuerstring := string
         LOCAL nI
         LOCAL zeichen           := ""
         LOCAL zeichensatz       := "!§$%&/()=?^*+'#<>,;.:-_\{}[] "
         LOCAL zeichenSatzLaenge := MAXLINE(zeichensatz)

         IF EMPTY(neuerstring)
            RETURN(.T.)
         ENDIF
         IF UPPER(SUBSTR(neuerstring,1,3)) = "DER" .OR.;
            UPPER(SUBSTR(neuerstring,1,3)) = "DIE" .OR.;
            UPPER(SUBSTR(neuerstring,1,3)) = "DAS" .OR.;
            UPPER(SUBSTR(neuerstring,1,3)) = "THE" .OR.;
            UPPER(SUBSTR(neuerstring,1,3)) = "THA" .OR.;
            UPPER(SUBSTR(neuerstring,1,3)) = "DE " .OR.;
            UPPER(SUBSTR(neuerstring,1,3)) = "LE " .OR.;
            UPPER(SUBSTR(neuerstring,1,3)) = "LA "
            neuerstring := POSDEL(neuerstring,1,3)
         ENDIF
         FOR nI := 1 TO zeichenSatzlaenge
             zeichen := SUBSTR(zeichensatz,nI,1)
             IF UPPER(Substr(neuerstring,1,1)) == UPPER(zeichen)
                neuerstring := POSDEL(neuerstring,1,1)
                nI := 0
                IF EMPTY(neuerstring)
                   EXIT
                ENDIF
             ENDIF
         NEXT
         neuelaenge := maxline(neuerstring)
         neuerstring += SPACE(altelaenge-neuelaenge)
         IF ! EMPTY(neuerstring)
            string := neuerstring
         ENDIF
         RETURN(string)
Das Schreiben in die DB ist nur zur Kontrolle um zu sehen, was übrigbleibt.
Sinn und Zweck der Routine soll es sein, einen Index aufzubauen, der Sonderzeichen und Artikel usw. am Anfang nicht berücksichtigt.
Es geht hier nur um die Routine, nicht um die Beachtung, ob der Schlüssel nachher von der Länge her paßt usw. Das ist alles schon fertig.
POSDEL() ist aus den Tools III. Früher waren die komplett in Assembler programmiert und somit sehr schnell. Wie das heute ist, weiß ich nicht.
Zuletzt geändert von Manfred am Do, 30. Jul 2009 12:55, insgesamt 1-mal geändert.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
andreas
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1902
Registriert: Mi, 28. Sep 2005 10:53
Wohnort: Osnabrück
Hat sich bedankt: 4 Mal
Kontaktdaten:

Beitrag von andreas »

Hallo Manfred,

ich würde vielleicht folgenden Code etwas verbessern:

Code: Alles auswählen

FOR nI := 1 TO zeichenSatzlaenge
             zeichen := SUBSTR(zeichensatz,nI,1)
             IF UPPER(Substr(neuerstring,1,1)) == UPPER(zeichen)
                neuerstring := POSDEL(neuerstring,1,1)
                nI := 0
                IF EMPTY(neuerstring)
                   EXIT
                ENDIF
             ENDIF
         NEXT
Neu:

Code: Alles auswählen

neuerstring := ""
FOR nI := 1 TO zeichenSatzlaenge
             zeichen := zeichensatz[nI]
             IF ! UPPER(zeichen) $ UPPER(zeichen)
                neuerstring += zeichen
             ENDIF
         NEXT
Gruß,

Andreas
VIP der XUG Osnabrück
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Beitrag von Manfred »

Hi Andreas,

es darf nur am Anfang geprüft werden. Das $ Zeichen prüft doch im ganzen String. Ich möchte nur die "Schrott" Zeichen filtern, die direkt am Anfang stehen, weil danach keiner sucht.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16509
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Manfred,
einige Kleinigkeiten sind mir aufgefallen (nicht unbedingt zum Tempo):
- ich sehe gerade, dass Andreas mir mit einem Beitrag schon ein Teil meines Postings abgenommen hat -
Außerdem:
statt

Code: Alles auswählen

string := titel->bez 
entfernen(@string)
würde ich der Einfachheit halber folgendes schreiben:

Code: Alles auswählen

string := entfernen( titel->bez )
Wobei noch zu überlegen wäre, ob nicht noch ein alltrim(...) sinnvoll wäre - wozu führende/folgende Leerzeichen mitgeben, da Du sie ja sowieso eliminierst??

Code: Alles auswählen

string := entfernen( alltrim( titel->bez ) )
In Deiner Funktion entfernen ist ein dicker Bug (der zum Tragen kommt, wenn Du sie so aufrufst, wie von mir vorgeschlagen):

Code: Alles auswählen

IF EMPTY(neuerstring) 
  RETURN(.T.) 
ENDIF
Das geht nicht! Muß dann heißen:

Code: Alles auswählen

IF EMPTY(neuerstring) 
  RETURN(neuerstring) 
ENDIF
Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16509
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Manfred,
Manfred hat geschrieben:Hi Andreas,

es darf nur am Anfang geprüft werden. Das $ Zeichen prüft doch im ganzen String. Ich möchte nur die "Schrott" Zeichen filtern, die direkt am Anfang stehen, weil danach keiner sucht.
gut, dann also statt:

Code: Alles auswählen

FOR nI := 1 TO zeichenSatzlaenge 
  zeichen := SUBSTR(zeichensatz,nI,1) 
  IF UPPER(Substr(neuerstring,1,1)) == UPPER(zeichen) 
    neuerstring := POSDEL(neuerstring,1,1) 
    nI := 0 
    IF EMPTY(neuerstring) 
      EXIT 
    ENDIF 
  ENDIF 
NEXT
lieber:

Code: Alles auswählen

IF UPPER(Substr(neuerstring,1,1)) $ UPPER(zeichen) 
  neuerstring := POSDEL(neuerstring,1,1) 
  nI := 0 
  IF EMPTY(neuerstring) 
    EXIT 
  ENDIF 
ENDIF 
Wobei Dein Code eh' nicht funktioniert, da Du immer nur das erste Zeichen prüfst - was passiert, wenn das zweite oder dritte ein solches Sonderzeichen wäre??

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Beitrag von Manfred »

Hi Martin,

wieso ist das ein Bug? Der Wert wird doch dann gar nicht angefaßt und somit auch nicht geändert. Reicht dann nicht ein RETURN(.T.)?

Zu Alltrim, hier fehlt natürlich das Vorhergehende: Es wird schon unterbunden am Anfang Leerzeichen zu haben. Es geht mir nachher nur darum, wenn ein "Sonderzeichen" entfernt wurde, dass dann nicht ein Leerzeichen übrigbleibt. ( "&% Text" würde dann ein " Text" übriglassen)
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16509
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Manfred,
es ist ein Bug, wenn Du die Funktion so aufrufst, wie ich es vorgeschlagen habe!
Abgesehen davon ist es im Moment so, dass Du bei Abbruch ein Boolean und beim ordnungsgemäßen Durchlauf eine Zeichenkette zurückgibst.

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Beitrag von Manfred »

Hi Martin,

nönö, da muß ich Dich enttäuschen. Die Funktion POSDEL() entfernt das Zeichen und schiebt dann von rechts nach links. Dann wird nI auf 0 gesetzt und es wird wieder von vorne angefangen. Das solange, bis entweder alle Zeichen verschwunden sind, oder der String leer ist und wieder auf den Ursprung zurückgesetzt wird. So sieht es jedenfalls nach Einsicht in die Ziel DB in dem Beispiel aus.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16509
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Manfred,
nein! Tut es definitiv nicht!
  • Du untersuchst von dem String soviele Zeichen, wie in Deinem String mit den Sonderzeichen drin sind (und nicht im String, der übergeben wurde)
  • Bei einem String a(lkklkklklk) würde gar nichts entfernt werden, da das erste Zeichen ein gültiges ist.
Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Beitrag von Manfred »

Hi Martin,
Martin Altmann hat geschrieben:Hallo Manfred,
es ist ein Bug, wenn Du die Funktion so aufrufst, wie ich es vorgeschlagen habe!
Deshalb frage ich ja, ich verstehe es nicht so ganz.
Abgesehen davon ist es im Moment so, dass Du bei Abbruch ein Boolean und beim ordnungsgemäßen Durchlauf eine Zeichenkette zurückgibst.

Viele Grüße,
Martin
Hm, das knallt aber nicht, oder ? Jedenfalls habe ich da nie drüber nachgedacht und werde jetzt zum 1.Mal darauf aufmerksam gemacht. Ich mache das die ganze Zeit so. Naja, sauber ist es nicht, da hast Du sicherlich Recht.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Beitrag von Manfred »

Hilfäää,

ich habe es gewußt. :shock:

Oben hatte ich erwähnt, dass nur am Anfang entfernt werden soll, als 1.Zeichen. Nie, niemals nicht mittendrin.

Die Funktion als solches klappt einwandfrei, ich wollte nur wissen, ob sie auch schnell ist, oder ob jemand eine Idee hat, wie man sie wenn, schneller machen kann.
Zuletzt geändert von Manfred am Mo, 23. Okt 2006 12:49, insgesamt 1-mal geändert.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16509
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Manfred,
im Moment knallt es nicht, da Du nicht den Rückgabewert der Funktion in die Datenbank schreibst, sondern das, was Du in die Datenbank schreibst, per Referenz übergibst.
Fasst Du die zwei Zeilen jedoch so zusammen, wie ich das vorgeschlagen habe, so schreibst Du den Rückgabewert in die Datenbank. Und dann darfst Du kein .t. zurückgeben!

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16509
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Manfred,
Manfred hat geschrieben:Oben hatte ich erwähnt, dass nur am Anfang entfernt werden soll, als 1.Zeichen. Nie, niemals nicht mittendrin.
Okok - dann mach' es so, wie ich geschrieben habe - mit $.
Ist bestimmt schneller, als die FOR-Schleife von Dir.

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Beitrag von Manfred »

Hi Martin,
Martin Altmann hat geschrieben:Hallo Manfred,
im Moment knallt es nicht, da Du nicht den Rückgabewert der Funktion in die Datenbank schreibst, sondern das, was Du in die Datenbank schreibst, per Referenz übergibst.
Fasst Du die zwei Zeilen jedoch so zusammen, wie ich das vorgeschlagen habe, so schreibst Du den Rückgabewert in die Datenbank. Und dann darfst Du kein .t. zurückgeben!

Viele Grüße,
Martin
alles klar, aber dies ist ja nur ein Beispiel, Nachher wird nur mit Vars gearbeitet.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Beitrag von Manfred »

Hi Martin,
Martin Altmann hat geschrieben:Hallo Manfred,
Manfred hat geschrieben:Oben hatte ich erwähnt, dass nur am Anfang entfernt werden soll, als 1.Zeichen. Nie, niemals nicht mittendrin.
Okok - dann mach' es so, wie ich geschrieben habe - mit $.
Ist bestimmt schneller, als die FOR-Schleife von Dir.

Viele Grüße,
Martin
hast total Recht. Ich habe nicht richtig gelesen und mich gefragt: "Was will er denn jetzt von dir?" Aber Du machst es andersherum. Alles klar, 2x hingesehen , Verstand angeschaltet und verstanden.

PS: Nö Stopp. Nochmal hingesehen und festgstellt, dass nur 1x geprüft wird. Es müssen aber alle Zeichen nacheinander geprüft werden. Es kann ja sein, dass die Zeichen genau so stehen, wie sie in der Varable stehe, die ich als Referenz nutze. Zumindest muß eine Schleife her, die solange läuft, bis die Var durch ist. Bei Deinem Vorschlag würde nur das erste gefunden Zeichen entfernt und dann ist nichts mehr. Oder bin ich blind?
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Hi Manfred,

was ich nicht verstehe ist, warum du nur am Anfang die unerwünschten Zeichen löschen willst, im Index brauchst du diese später doch auch nicht mehr oder ? Und deinen Indexbegriff erweiterst du ja auf die nötige Länge.

Wenn das so ist, sind mehrere STRTRAN Aufrufe das schnellste was man machen kann:

Code: Alles auswählen

cTxt := upper(cTxt)   // der INDEX wird einmal UPPER gesetzt.
cTxt := strTran(cTxt, "DER ", "")
cTxt := strTran(cTxt, "DIE ", "")
...
cTxt := strTran(cTxt, "$", "")
...
cTxt := ltrim(cTxt)
Aber ein Problem habe ich bei dir gesehen, ich suche oben nach 'DER ', du nach 'DER', DEREK würde bei Dir zu EK verkürzt werden, wenn ich nicht was übersehen habe ;)
Gruß
Hubert
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16509
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Manfred,
sorry - gerade erst gesehen, dass Du Dein Posting nachträglich editiert hast!
Manfred hat geschrieben:PS: Nö Stopp. Nochmal hingesehen und festgstellt, dass nur 1x geprüft wird. Es müssen aber alle Zeichen nacheinander geprüft werden. Es kann ja sein, dass die Zeichen genau so stehen, wie sie in der Varable stehe, die ich als Referenz nutze. Zumindest muß eine Schleife her, die solange läuft, bis die Var durch ist. Bei Deinem Vorschlag würde nur das erste gefunden Zeichen entfernt und dann ist nichts mehr. Oder bin ich blind?
Dann nimm einfach eine Do while:

Code: Alles auswählen

DO WHILE UPPER(Substr(neuerstring,1,1)) $ UPPER(zeichen) 
  neuerstring := POSDEL(neuerstring,1,1) 
  IF EMPTY(neuerstring) 
    EXIT 
  ENDIF 
ENDDO
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Beitrag von Manfred »

Hi Hubert,
brandelh hat geschrieben:Hi Manfred,

was ich nicht verstehe ist, warum du nur am Anfang die unerwünschten Zeichen löschen willst, im Index brauchst du diese später doch auch nicht mehr oder ? Und deinen Indexbegriff erweiterst du ja auf die nötige Länge.
Am Anfang nur, weil keinem zuzumuten ist, dass er/sie sich Gedanken darüber macht, ob und wie der Anfang geschrieben ist. Es steht manchmal so ein Schrott dadrin, das einem die Haare zu Berge stehen. Die Daten kommen von Fremdanbietern und darauf habe ich keinen Einfluß. Ich kann halt nur weiterverabeiten. Ich eliminiere die Schrottdaten nur aus dem Key. Sie bleiben weiterhin dort, wo sie standen in der DB. Wenn gesucht wird, dann würde bei "Der Wolf", dieses unter W erscheinen, aber mit dem "Der" davor.
Wenn das so ist, sind mehrere STRTRAN Aufrufe das schnellste was man machen kann:

Code: Alles auswählen

cTxt := upper(cTxt)   // der INDEX wird einmal UPPER gesetzt.
cTxt := strTran(cTxt, "DER ", "")
cTxt := strTran(cTxt, "DIE ", "")
...
cTxt := strTran(cTxt, "$", "")
...
cTxt := ltrim(cTxt)
Aha, das wollte ich wissen, ob es mit einer anderen Funktion schneller geht. Aber wieso mit StrTran() ? Woher weißt Du das?
Aber ein Problem habe ich bei dir gesehen, ich suche oben nach 'DER ', du nach 'DER', DEREK würde bei Dir zu EK verkürzt werden, wenn ich nicht was übersehen habe ;)
Du hast Recht, aber es war ein Tippfehler, es war nicht so gewollt. Natürlich "DER " "DIE " usw.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Hallo Manfred,

als ich damals meine KeinUmlaut() Funktion geschrieben habe, hatte ich zuerst eine ForNext Schleife die den Suchbegriff Zeichen für Zeichen durchlaufen hat. Damals habe ich probiert, was schneller ist ...

Code: Alles auswählen

for x := 1 to nTextLen
     do case
          case "ä" $ ....
oder

Code: Alles auswählen

cTxt := StrTran(cTxt,"ä","ae")
cTxt := StrTran(cTxt,"ö","oe")
nur bei sehr kurzen Strings war ForNext schnell genug. StrTran() arbeitet bei einem Aufruf den ganzen String ab, das ist schneller als 2 oder 3 Suchaufrufe (at() etc.) und dann mehrfaches Umkopieren mit alltrim(substr(cTxt,4)) ...
Und wenn du bei den Suchbegriffen die Sonderzeichen und Artikel eliminieren willst, kannst du das für den Index auch im ganzen Index tun.
Da Indexdateien auch Platz brauchen, würde ich eh auf 10 bis 15 Zeichen begrenzen und dann hast du dort auch nur interessante Worte.

Wenn du auf 20 bis 30 Zeichen gehst, und die unnötigen entfernst könntest du mit OrdWildSeek() auch eine Art von Volltext suche ermöglichen ;)
Gruß
Hubert
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Beitrag von AUGE_OHR »

hi,

hoffe das ich nichts über"lesen" habe, aber ich würde erstmal die
"Suchbegriffe" (DER,DIE ...) in ein Array packen.
danach mit ASCAN() festellen ob ein Element zutrifft und mit AT()
und STRTRAN() die Zeichen "auswechseln"

gruss by OHR
Jimmy
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Hi Jimmy,

unter Basic hätte ich das früher auch so gemacht und mußte unter Clipper / Xbase++ feststellen, dass die For/Next Stringsuche und Verarbeitung nicht gerade zu den schnellsten Dingen gehören ;).

Aber die mächtigen Assembler-Befehle wie aSort() oder StrTran(), das sind die Stärken von Xbase++ .

StrTran() sucht UND ersetzt rasend schnell, wenn es was zu ersetzten gibt, ansonsten macht es nichts, also nicht erst alle Begriffe in ein Array und mit $ oder AT() suchen, sondern gleich mit StrTran() auf Verdacht alle möglichen Begriffe (gibt dann halt ein paar Aufrufe mehr) austauschen lassen.
Ein Aufruf je Begriff für den ganzen String ist allemal schneller, als jedes einzelne Byte des Strings in einem Array zu suchen, oder Von/Bis Werte zu ermitteln um dann den String auszutauschen.

Ich erhalte regelmäßig z.B. 1 GB große Textdatei, die ich zeilenweise einlesen und interpretieren muss. 128 Byte feste Zeilenlänge und ab und an CHR(0) oder CHR(26) im Text, da alte gepackte Zahlenfelder vorkamen. Da die meisten Zeilen mit weniger als 30 Zeichen auskommen, sind also etwa 2/3 Blanks. Die Datei muß also vor der eigentlichen Verarbeitung verkleinert werden ...

Hier meine schnellste Lösung - ich habe 2 GB im Rechner ;) :

Code: Alles auswählen

cTxt := memoread("1GBDatei")
cTxt := strTran(cTxt,chr(0)," ") // säubern
cTxt := strTran(cTxt,chr(26)," ") // säubern
cTxt := strTran(cTxt,space(60)," ") // zuerst die wirklich großen Strings
cTxt := strTran(cTxt,space(25)," ") 
do while space(5) $ cTxt
    cTxt := strTran(cTxt,space(5)," ") 
enddo
do while space(2) $ cTxt
    cTxt := strTran(cTxt,space(2)," ") 
enddo
Natürlich hängt die Geschwindigkeit hier sehr stark von der Verteilung der langen und kurzen Zeilen ab, da habe ich etwas gespielt. Aber die wenigen StrTran() Aufrufe auf den riesigen String werden in Minuten erledigt und ich habe eine etwa 300 MB Datei mit flexibler Satzlänge über.
Hätte ich das versucht mit MLCount() oder satzweisem Lesen von Festplatte zu Festplatte wären viele Stunden nötig gewesen (die ersten Versuche mit meinem dafür eigentlich geeigneten PowerBasic habe ich schon bald abgebrochen). Außerdem verhindern chr(0) und chr(26) massiv die Funktionen für zeilenweises einlesen.

Ich vermute aber, dass die Daten von Manfred maximal eher in 1000 Stückzahlen verarbeitet werden, dann spielt das alles keine Rolle.
Gruß
Hubert
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Beitrag von AUGE_OHR »

hi,
brandelh hat geschrieben: ... also nicht erst alle Begriffe in ein Array und mit $ oder AT() suchen, sondern gleich mit StrTran() auf Verdacht alle möglichen Begriffe (gibt dann halt ein paar Aufrufe mehr) austauschen lassen.
bei CHR(0) oder so gebe ich dir völlig recht, aber der "Begriff" könnte
ja mehrfach im selben Text vorkommen und man will nur "einen"
ausstauschen. Insofern ist der "nStart" Parameter bei STRTRAN()
durchaus sehr nützlich.

gruss by OHR
Jimmy
Benutzeravatar
Wolfgang Ciriack
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2934
Registriert: Sa, 24. Sep 2005 9:37
Wohnort: Berlin
Hat sich bedankt: 13 Mal
Danksagung erhalten: 34 Mal
Kontaktdaten:

Beitrag von Wolfgang Ciriack »

Und um einzelne Zeichen zu entfernen könnte man auch charrem() aus den Tools nehmen.
Viele Grüße
Wolfgang
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Beitrag von Manfred »

Hi,

ich muß hier jetzt nochmals kurz bremsen. Ich habe den Verdacht, dass etwas schief läuft.

Also nochmals in aller Kürze.

Die Zeichen, die "entfernt" werden sollen, sollen nur im Index verschwunden sein, weil sonst manche Titel später keinen Sinn mehr ergeben. Habe ich alles schon ausprobiert. Ich schätze einfach einmal, das bestimmte Interpreten bei ihrer Titelwahl einfach zu viel Drogen genommen haben. ;-)

Also fällt hiermit der Vorschlag von Hubert mit der Eliminierung komplett schon mal weg. Ich benutze als Index CDX Treiber und lasse ebenso 50 Zeichen zu, wie die DB Spalte breit ist. Die Titel, die in Frage kommen sind teilweise erst ab der 20. oder 30. Stelle unterschiedlich, weil dann erst die Angabe der Ausgabe, bzw. der Nummer des Teils angegeben wird.
Die DB, auf die der Index aufgebaut werden soll haben einige 100.000 Datensätze. D.H. also, beim Aufbau des Index wird die Funktion dementsprechend oft angesprungen.
Weiterhin wird die Funktion, bei jedem Suchen in der DB, angesprungen, um den String entsprechend des zu erwartenden Schlüssels zu konvertieren.

Ich habe mir nochmals das Handbuch angesehen, da steht auch noch Stuff() drin.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Beitrag von AUGE_OHR »

hi,
Manfred hat geschrieben: ... Die Zeichen, die "entfernt" werden sollen, sollen nur im Index verschwunden sein ...
yup schon klar, ist im Prinzip mein "Telefonnummer" Problem :)
Manfred hat geschrieben: Ich benutze als Index CDX Treiber und lasse ebenso 50 Zeichen zu
klar muss man die "entfernten" Zeichen wieder "auffüllen", aber ich
hänge die dann "hinten" ran
Manfred hat geschrieben: D.H. also, beim Aufbau des Index wird die Funktion dementsprechend
oft angesprungen.
eine UDF im Index ist leider nie sehr schnell :(
Manfred hat geschrieben: Ich habe mir nochmals das Handbuch angesehen, da steht auch noch
Stuff() drin.
STUFF() v. STRTRAN() ... also unter Cl*pper war STRTRAN() deutlich
schneller ... ich habe den "alten" Code für Xbase++ übernommen ...

gruss by OHR
Jimmy
Antworten