XbPCRE

Aus Wiki des Deutschsprachige Xbaseentwickler e. V.
Version vom 5. September 2013, 13:38 Uhr von Georg (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen


XbPCRE - eine Pearl Compatible Regular Expression Library

PCRE ist eine frei verfügbare DLL, die mit Pearl kompatible Regular Expressions zur Verfügung stellt.

Während Xbase nur ein Standard-Matching bereit stellt, d.h. nur Vergleiche auf einer 1:1 Basis ermöglicht, muss man wenn es um Pattern (Muster, wie bei der Verwendung von Wildcards) geht, entweder die Segel streichen oder PCRE oder eine andere Bibliothek verwenden.


Syntax und Übersichten

Sind in der XbPCRE-Hilfe enthalten und werden hier nicht wiederholt.


Beispielprogramm

Das folgende Programm stellt quasi eine Workbench zur Verfügung, in der man das Verhalten von Regular Expressions ausprobieren kann. Der erste Teil ergibt die AppSys.prg, und der zweite Teil das eigentliche Programm.

#INCLUDE "AppEvent.CH"
#INCLUDE "NLS.CH"
#INCLUDE "Xbp.CH"
FUNCTION AppSys()
  Local aSize, oDlg, aPos[2], aSizeNew[2], nI
  aSize := AppDesktop():currentSize()
  FOR nI := 1 TO 2
     aSizeNew[nI] := Int(aSize[nI] * 0.6)
  NEXT
  IF aSizeNew[1] < 800
     aSizeNew[1] := 800
  ENDIF
  IF aSizeNew[2] < 600
     aSizeNew[2] := 600
  ENDIF
  aPos[1] := Int((aSize[1] - aSizeNew[1]) / 2)
  aPos[2] := Int((aSize[2] - aSizeNew[2]) / 2)
  oDlg := XbpDialog():new(AppDesktop(), AppDesktop(), aPos, aSizeNew, , .F.)
  oDlg:sysmenu := .T.
  oDlg:hideButton := .T.
  oDlg:taskList := .T.
  oDlg:close := {|| CleanUpAfter(), WinManKill(), _QUIT()}
  oDlg:title := ""
  // oDlg:icon := 2001
  oDlg:create()
  RootWindow(oDlg)
  oDlg:setTitle(GetProgramTitle())
  oDlg:drawingArea:scrollBars := XBP_SCROLLBAR_VERT
  oDlg:show()
  SetAppWindow(oDlg)
RETURN (.T.)

FUNCTION RootWindow(oDlg)
  Static oStatic
  IF oDlg <> NIL
     oStatic := oDlg
  ENDIF
  IF oStatic = NIL
     ConfirmBox(, "Fehler", "Programm nicht richtig geladen", XBPMB_CRITICAL, XBPMB_OK)
     QUIT
  ENDIF
RETURN (oStatic)


#DEFINE ENTRY_DATA                1
#DEFINE ENTRY_PATTERN             ENTRY_DATA + 1
#DEFINE ENTRY_OFFSET              ENTRY_PATTERN + 1
#DEFINE ENTRY_BUTTON              ENTRY_OFFSET + 1
#DEFINE ENTRY_RESULTS             ENTRY_BUTTON + 1
#DEFINE ENTRY_SPIN                ENTRY_RESULTS + 1
#DEFINE ENTRY_POS1                ENTRY_SPIN + 1
#DEFINE ENTRY_POS2                ENTRY_POS1 + 1
#DEFINE ENTRY_STRING              ENTRY_POS2 + 1
#DEFINE ENTRY_REGEXP              ENTRY_STRING + 1
#DEFINE ENTRY_OFFSET_VALUE        ENTRY_REGEXP + 1

#DEFINE ENTRY_CASELESS            ENTRY_OFFSET_VALUE + 1
#DEFINE ENTRY_MULTILINE           ENTRY_CASELESS + 1
#DEFINE ENTRY_DOTALL              ENTRY_MULTILINE + 1
#DEFINE ENTRY_EXTENDED            ENTRY_DOTALL + 1
#DEFINE ENTRY_ANCHORED            ENTRY_EXTENDED + 1
#DEFINE ENTRY_DOLLAR_ENDONLY      ENTRY_ANCHORED + 1
#DEFINE ENTRY_EXTRA               ENTRY_DOLLAR_ENDONLY + 1
#DEFINE ENTRY_NOTBOL              ENTRY_EXTRA + 1
#DEFINE ENTRY_NOTEOL              ENTRY_NOTBOL + 1
#DEFINE ENTRY_UNGREEDY            ENTRY_NOTEOL + 1
#DEFINE ENTRY_NOTEMPTY            ENTRY_UNGREEDY + 1
#DEFINE ENTRY_UTF8                ENTRY_NOTEMPTY + 1

#INCLUDE "AppEvent.CH"
#INCLUDE "FileIO.CH"
#INCLUDE "Xbp.CH"

#INCLUDE "XbpCRE.CH"

#PRAGMA LIBRARY("XbpCRE.LIB")

FUNCTION Main()
  Local mp1, mp2
  Local nEvent
  Local oXbp
  GenDialog()
  nEvent := xbe_None
  WHILE nEvent <> xbeP_Close
     nEvent := AppEvent(@mp1, @mp2, @oXbp)
     oXbp:handleEvent(nEvent, mp1, mp2)
  END
RETURN (.T.)

FUNCTION GenDialog()
  Local aPos, aSize, aBaseSize, aEntries, aPosIn, aSizeIn
  Local nSizeHigh, nI
  Local oXbp, oDlg, oGroup
  oDlg := RootWindow():drawingArea
  aBaseSize := oDlg:currentSize()
  aEntries := {}
  // Erzeugen des Eingabefeldes für den zu durchsuchenden Text
  aPos := {10, aBaseSize[2] - 160}
  aSize := {aBaseSize[1] - 20, 150}
  oGroup := XbpStatic():new(oDlg, oDlg, aPos, aSize)
  oGroup:type := XBPSTATIC_TYPE_GROUPBOX
  oGroup:caption := "enter/drag drop text to search"
  oGroup:create()
  aPosIn := AClone(aPos)
  aSizeIn := AClone(aSize)
  ReSizeLocation(aPosIn, aSizeIn)
  oXbp := XbpMLE():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:tabStop := .T.
  oXbp:ignoreTab := .T.
  oXbp:dropZone := .T.
  oXbp:dragEnter := {|aState, oData, self| CheckDragDrop(aState, oData, self)}
  oXbp:dragDrop := {|aState, oData, self| HandleDragDrop(aState, oData, self)}
  oXbp:create()
  AAdd(aEntries, oXbp)
  // Erzeugen des Eingabefeldes für das Pattern
  nSizeHigh := 40
  aPos[2] -= nSizeHigh
  aPos[2] -= 10
  aSize[2] := nSizeHigh
  oGroup := XbpStatic():new(oDlg, oDlg, aPos, aSize)
  oGroup:type := XBPSTATIC_TYPE_GROUPBOX
  oGroup:caption := "enter search pattern (regular expression)"
  oGroup:create()
  aPosIn := AClone(aPos)
  aSizeIn := AClone(aSize)
  ReSizeLocation(aPosIn, aSizeIn)
  oXbp := XbpSLE():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:tabStop := .T.
  oXbp:bufferLength := 256
  oXbp:create()
  AAdd(aEntries, oXbp)
  // Erzeugen des Eingabefeldes für den Offset
  // da ein Spinbutton maximal 99.999 abbilden kann, wird ein Textfeld für die
  // Eingabe verwendet:
  nSizeHigh := 40
  aPos[2] -= nSizeHigh
  aPos[2] -= 10
  aSize := {160, nSizeHigh}
  oGroup := XbpStatic():new(oDlg, oDlg, aPos, aSize)
  oGroup:type := XBPSTATIC_TYPE_GROUPBOX
  oGroup:caption := "select offset for search operation"
  oGroup:create()
  aPosIn := AClone(aPos)
  aSizeIn := AClone(aSize)
  ReSizeLocation(aPosIn, aSizeIn)
  oXbp := XbpSLE():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:tabStop := .T.
  oXbp:create()
  oXbp:setData("1")
  AAdd(aEntries, oXbp)
  // Erzeugen eines Pushbuttons, um einen Test auszuführen
  nSizeHigh := 30
  aPos[2] -= nSizeHigh
  aPos[2] -= 10
  aSize := {120, nSizeHigh}
  oXbp := XbpPushButton():new(oDlg, oDlg, aPos, aSize)
  oXbp:caption := "Try it!"
  oXbp:tabStop := .T.
  oXbp:activate := {|| RunRegExp(aEntries)}
  oXbp:create()
  AAdd(aEntries, oXbp)
  // Anzeige der Matches
  nSizeHigh := 40
  aPos[2] -= nSizeHigh
  aPos[2] -= 10
  aSize := {210, nSizeHigh}
  oGroup := XbpStatic():new(oDlg, oDlg, aPos, aSize)
  oGroup:type := XBPSTATIC_TYPE_GROUPBOX
  oGroup:caption := "result from executing RegExp"
  oGroup:create()
  aPosIn := AClone(aPos)
  aSizeIn := AClone(aSize)
  ReSizeLocation(aPosIn, aSizeIn)
  oXbp := XbpStatic():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:type := XBPSTATIC_TYPE_TEXT
  oXbp:options := XBPSTATIC_TEXT_CENTER
  oXbp:caption := "??"
  oXbp:create()
  AAdd(aEntries, oXbp)
  // Auswahl der Matches über einen Spinbutton
  aPos[1] += 10 + aSize[1]
  aSize := {180, nSizeHigh}
  oGroup := XbpStatic():new(oDlg, oDlg, aPos, aSize)
  oGroup:type := XBPSTATIC_TYPE_GROUPBOX
  oGroup:caption := "result from RegExp:Exec()"
  oGroup:create()
  aPosIn := AClone(aPos)
  aSizeIn := AClone(aSize)
  ReSizeLocation(aPosIn, aSizeIn)
  oXbp := XbpSpinButton():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:tabStop := .T.
  oXbp:down := {|| SwitchDisplay(aEntries)}
  oXbp:up := {|| SwitchDisplay(aEntries)}
  oXbp:setNumLimits(0, 0)
  oXbp:create()
  AAdd(aEntries, oXbp)
  // Anzeige der Position, wo der Match gefunden wurde
  aPos[1] += 10 + aSize[1]
  aSize := {100, nSizeHigh}
  oGroup := XbpStatic():new(oDlg, oDlg, aPos, aSize)
  oGroup:type := XBPSTATIC_TYPE_GROUPBOX
  oGroup:caption := "starting point"
  oGroup:create()
  aPosIn := AClone(aPos)
  aSizeIn := AClone(aSize)
  ReSizeLocation(aPosIn, aSizeIn)
  oXbp := XbpStatic():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:type := XBPSTATIC_TYPE_TEXT
  oXbp:options := XBPSTATIC_TEXT_CENTER
  oXbp:caption := "??"
  oXbp:create()
  AAdd(aEntries, oXbp)
  // Anzeige der Länge des Matches
  aPos[1] += 10 + aSize[1]
  oGroup := XbpStatic():new(oDlg, oDlg, aPos, aSize)
  oGroup:type := XBPSTATIC_TYPE_GROUPBOX
  oGroup:caption := "length"
  oGroup:create()
  aPosIn := AClone(aPos)
  aSizeIn := AClone(aSize)
  ReSizeLocation(aPosIn, aSizeIn)
  oXbp := XbpStatic():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:type := XBPSTATIC_TYPE_TEXT
  oXbp:options := XBPSTATIC_TEXT_CENTER
  oXbp:caption := "??"
  oXbp:create()
  AAdd(aEntries, oXbp)
  // Anzeige des Ergebnis-Strings (bzw. eines Teils davon)
  nSizeHigh := 40
  aPos[1] := 10
  aPos[2] -= nSizeHigh
  aPos[2] -= 10
  aSize := {aBaseSize[1] - 20, nSizeHigh}
  oGroup := XbpStatic():new(oDlg, oDlg, aPos, aSize)
  oGroup:type := XBPSTATIC_TYPE_GROUPBOX
  oGroup:caption := "result"
  oGroup:create()
  aPosIn := AClone(aPos)
  aSizeIn := AClone(aSize)
  ReSizeLocation(aPosIn, aSizeIn)
  oXbp := XbpStatic():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:type := XBPSTATIC_TYPE_TEXT
  oXbp:options := XBPSTATIC_TEXT_LEFT
  oXbp:caption := "??"
  oXbp:create()
  AAdd(aEntries, oXbp)
  // Erzeugen zweiter Platzhalter für das RegExp-Objekt und den Offset
  AAdd(aEntries, NIL)
  AAdd(aEntries, 1)
  // Erzeugen von Checkboxen zum Setzen diverser RegEx-Optionen:
  nSizeHigh := 140
  aPos[1] := 10
  aPos[2] -= nSizeHigh
  aPos[2] -= 10
  aSize := {aBaseSize[1] - 20, nSizeHigh}
  oGroup := XbpStatic():new(oDlg, oDlg, aPos, aSize)
  oGroup:type := XBPSTATIC_TYPE_GROUPBOX
  oGroup:caption := "PCRE options"
  oGroup:create()

  nSizeHigh := 30
  aPosIn := {10, 95}
  aSizeIn := {180, nSizeHigh}
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_CASELESS"
  oXbp:create()
  AAdd(aEntries, oXbp)
  oXbp:setData(.T.)

  aPosIn[1] += aSizeIn[1]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_MULTILINE"
  oXbp:create()
  AAdd(aEntries, oXbp)
  oXbp:setData(.T.)

  aPosIn[1] += aSizeIn[1]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_DOTALL"
  oXbp:create()
  AAdd(aEntries, oXbp)
  oXbp:setData(.T.)

  aPosIn[1] += aSizeIn[1]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_EXTENDED"
  oXbp:create()
  AAdd(aEntries, oXbp)

  aPosIn[1] := 10
  aPosIn[2] -= aSizeIn[2]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_ANCHORED"
  oXbp:create()
  AAdd(aEntries, oXbp)

  aPosIn[1] += aSizeIn[1]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_DOLLAR_ENDONLY"
  oXbp:create()
  AAdd(aEntries, oXbp)

  aPosIn[1] += aSizeIn[1]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_EXTRA"
  oXbp:create()
  AAdd(aEntries, oXbp)

  aPosIn[1] += aSizeIn[1]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_NOTBOL"
  oXbp:create()
  AAdd(aEntries, oXbp)

  aPosIn[1] := 10
  aPosIn[2] -= aSizeIn[2]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_NOTEOL"
  oXbp:create()
  AAdd(aEntries, oXbp)

  aPosIn[1] += aSizeIn[1]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_UNGREEDY"
  oXbp:create()
  AAdd(aEntries, oXbp)

  aPosIn[1] += aSizeIn[1]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_NOTEMPTY"
  oXbp:create()
  AAdd(aEntries, oXbp)

  aPosIn[1] += aSizeIn[1]
  oXbp := XbpCheckBox():new(oGroup, oGroup, aPosIn, aSizeIn)
  oXbp:caption := "PCRE_UTF8"
  oXbp:create()
  AAdd(aEntries, oXbp)

  SetAppFocus(aEntries[1])
RETURN (.T.)

FUNCTION RunRegExp(aEntries)
  Local aPos
  Local cData, cPattern, cResult
  Local nResult, nRegExpOptions, nOffset
  Local oReg
  // prüfen, ob Daten eingegeben wurden
  cData := aEntries[1]:getData()
  IF Empty(cData)
     ConfirmBox(, "No data defined for searching, please correct and re-try", "Error", XBPMB_OK, XBPMB_CRITICAL)
     RETU(.F.)
  ENDIF
  // prüfen, ob ein Pattern eingegeben wurde
  cPattern := aEntries[2]:getData()
  IF Empty(cPattern)
     ConfirmBox(, "No search pattern defined, please correct and re-try", "Error", XBPMB_OK, XBPMB_CRITICAL)
     RETU(.F.)
  ENDIF
  // Ermitteln des Offset
  nOffset := Val(aEntries[3]:getData())
  IF Empty(nOffSet) .OR. nOffSet < 1
     nOffSet := 1
  ENDIF
  // Ermitteln der Optionen, die aktiviert werden sollen:
  nRegExpOptions := 0
  IF aEntries[ENTRY_CASELESS]:getData()
     nRegExpOptions += PCRE_CASELESS
  ENDIF
  IF aEntries[ENTRY_MULTILINE]:getData()
     nRegExpOptions += PCRE_MULTILINE
  ENDIF
  IF aEntries[ENTRY_DOTALL]:getData()
     nRegExpOptions += PCRE_DOTALL
  ENDIF
  IF aEntries[ENTRY_EXTENDED]:getData()
     nRegExpOptions += PCRE_EXTENDED
  ENDIF
  IF aEntries[ENTRY_ANCHORED]:getData()
     nRegExpOptions += PCRE_ANCHORED
  ENDIF
  IF aEntries[ENTRY_DOLLAR_ENDONLY]:getData()
     nRegExpOptions += PCRE_DOLLAR_ENDONLY
  ENDIF
  IF aEntries[ENTRY_EXTRA]:getData()
     nRegExpOptions += PCRE_EXTRA
  ENDIF
  IF aEntries[ENTRY_NOTBOL]:getData()
     nRegExpOptions += PCRE_NOTBOL
  ENDIF
  IF aEntries[ENTRY_NOTEOL]:getData()
     nRegExpOptions += PCRE_NOTEOL
  ENDIF
  IF aEntries[ENTRY_UNGREEDY]:getData()
     nRegExpOptions += PCRE_UNGREEDY
  ENDIF
  IF aEntries[ENTRY_NOTEMPTY]:getData()
     nRegExpOptions += PCRE_NOTEMPTY
  ENDIF
  IF aEntries[ENTRY_UTF8]:getData()
     nRegExpOptions += PCRE_UTF8
  ENDIF
  // Erzeugen eines RegExp() Objekts, und Ausführung desselben
  oReg := RegExp():new(cPattern, nRegExpOptions)
  nResult := oReg:exec(cData, nOffSet)
  // Darstellung des Ergebnisses in der Maske
  cResult := Str(nResult)
  aEntries[5]:caption := cResult
  aEntries[5]:configure()
  // wenn kein Treffer gefunden wurde, werden bestimmte Elemente zurückgesetzt
  IF nResult < 1
     aEntries[6]:setNumLimits(0, 0)
     aEntries[6]:disable()
     aEntries[7]:caption := "???"
     aEntries[7]:configure()
     aEntries[8]:caption := "???"
     aEntries[8]:configure()
     aEntries[11] := nOffSet
  ELSE
  // wenn Treffer gefunden wurden, wird das erste Ergebnis angezeigt, und 
  // die Anzeige weiterer ermöglicht:
     aEntries[6]:enable()
     aPos := oReg:Result(1)
     aEntries[6]:setNumLimits(0, nResult)
     aEntries[6]:setData(1)
     aEntries[7]:caption := Str(aPos[1])
     aEntries[7]:configure()
     aEntries[8]:caption := Str(aPos[2])
     aEntries[8]:configure()
     aEntries[9]:caption := Substr(cData, aPos[1], aPos[2])
     aEntries[9]:configure()
     aEntries[11] := nOffSet
  ENDIF

  aEntries[10] := oReg

RETURN (.T.)

FUNCTION SwitchDisplay(aEntries)
  Local aPos
  Local nValue
  // wenn der Spinbutton verändert wurde, wird diese Routine aufgerufen, um die
  // korrespondierenden Werte abzurufen:
  nValue := aEntries[6]:getData()
  IF nValue > 0
     aPos := aEntries[10]:Result(nValue)
     aEntries[7]:caption := Str(aPos[1])
     aEntries[7]:configure()
     aEntries[8]:caption := Str(aPos[2])
     aEntries[8]:configure()
     aEntries[9]:caption := Substr(aEntries[1]:getData(), aPos[1], aPos[2])
     aEntries[9]:configure()
  ENDIF
RETURN (aEntries) 

FUNCTION CheckDragDrop(aState, oData, oMLE)
  // nur Text oder eine Dateiliste sind zulässig Objekte, die per Drag and Drop verschoben
  // werden können
  DO CASE
  CASE oData:QueryGetFormat(XBPCLPBRD_FILELIST) == .T.
     RETU(XBP_DROPMODE_COPY)
  CASE oData:QueryGetFormat(XBPCLPBRD_TEXT) == .T.
     RETU(XBP_DROPMODE_COPY)
  ENDCASE
RETURN (XBP_DROPMODE_NONE) 

FUNCTION HandleDragDrop(aState, oData, oMLE)
  // das Feld mit dem Suchtext kann durch Tastatur oder Drag and Drop einer Datei oder eines
  // markierten Textes gefüllt werden. Drag and Drop ersetzt vorherige Daten.
  Local aFiles
  Local cFile, cContent
  Local nHandle, nSize

  DO CASE
  CASE oData:QueryGetFormat(XBPCLPBRD_FILELIST) == .T.
     aFiles := oData:GetData(XBPCLPBRD_FILELIST)
     cFile := aFiles[1]
     nHandle := fOpen(cFile, FO_READ)
     IF nHandle < 0
        RETU(.F.)
     ENDIF
     nSize := fSize(nHandle)
     cContent := Space(nSize)
     fRead(nHandle, @cContent, nSize)
     fClose(nHandle)
     oMLE:setData(cContent)
  CASE oData:QueryGetFormat(XBPCLPBRD_TEXT) == .T.
     cContent := oData:getData(XBPCLPBRD_TEXT)
     oMLE:setData(cContent)
  ENDCASE

RETURN (.T.)

FUNCTION CleanUpAfter()
RETURN (.T.)

FUNCTION GetProgramTitle()
  Local cTitle
  cTitle := "RegExp-Testlab"
RETURN (cTitle) 

FUNCTION ReSizeLocation(aPosIn, aSizeIn)
  Local nI
  // Ermitteln der Position innerhalb der GroupBox, an der Xbase-Parts angezeigt werden sollen
  FOR nI := 1 TO 2
     aSizeIn[nI] -= 20
     aPosIn[nI]  := 5
  NEXT
RETURN (.T.)

FUNCTION WinManKill()
RETURN (.T.)


Download

Von der Alaska Website