{"id":55001119,"date":"2018-02-01T00:00:00","date_gmt":"2022-03-08T18:32:33","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1119"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Volltextsuche_mit_Fundstellen","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/","title":{"rendered":"Volltextsuche mit Fundstellen"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg06.met.vgwort.de\/na\/5069ba44aae74c40a54f1cbd9128f3e7\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p class=\"image\">\n<p><b>Neulich wollte ich mal meine Artikeldatenbank nach bestimmten Suchbegriffen durchforsten. Also habe ich mir eine Abfrage gebaut, die nur die relevanten Felder der zu durchsuchenden Tabelle enth&auml;lt. Dort dachte ich dann, ich k&ouml;nnte mit der eingebauten Filter-Funktion des Datenblatts schnell zu den gesuchten Fundstellen gelangen. Das Ergebnis war ern&uuml;chternd, denn Access lieferte zwar alle passenden Datens&auml;tze, aber in den recht langen Texten innerhalb der Datens&auml;tze musste ich dann nochmals nach dem gesuchten Text suchen. Das konnte ich nicht auf mir sitzen lassen und habe eine Suchfunktion mit Fundstellen programmiert, die dieser Beitrag vorstellt.<\/b><\/p>\n<p>Normalerweise w&uuml;rde man im Datenblatt mit der Maus auf Pfeil nach unten rechts im Spaltenkopf klicken, dann den Men&uuml;eintrag <b>Textfilter|Enth&auml;lt&#8230; <\/b>ausw&auml;hlen, den Suchbegriff eingeben und dann die Suchergebnisse betrachten. Das gelingt auch grunds&auml;tzlich, wie Bild 1 zeigt. Aber wie eingangs erw&auml;hnt, wird auf diese Weise nicht die Fundstelle markiert.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_1119_001.png\" alt=\"Filtern nach Suchausdruck\" width=\"649,559\" height=\"329,2489\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Filtern nach Suchausdruck<\/span><\/b><\/p>\n<p>Dies erreichen wir etwas besser, wenn wir die <b>Suchen und Ersetzen<\/b>-Funktion nutzen, die wir &uuml;ber den Ribbon-Eintrag <b>Start|Suchen|Suchen <\/b>&ouml;ffnen. Diese springt so zur Fundstelle, dass diese meist ganz unten im sichtbaren Teil des Textes angezeigt wird (s. Bild 2). Auch das ist nur bedingt praxistauglich, da so nur jeweils ein Eintrag gleichzeitig angezeigt wird. Also ben&ouml;tigen wir eine alternative L&ouml;sung.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_1119_002.png\" alt=\"Einsatz der Suchen und Ersetzen-Funktion\" width=\"649,559\" height=\"332,6279\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Einsatz der Suchen und Ersetzen-Funktion<\/span><\/b><\/p>\n<h2>Ziel<\/h2>\n<p>Statt der nicht perfekten L&ouml;sung durch die eingebauten Elemente der Access-Datenblattansicht wollen wir eine benutzerdefinierte L&ouml;sung entwickeln. Diese soll die Fundstellen ebenfalls in einer Datenblattansicht anzeigen. Allerdings wollen wir auch nur die Fundstelle erhalten und nicht den kompletten Text des durchsuchten Inhalts.<\/p>\n<p>Und der gesuchte Begriff soll farbig hervorgehoben werden, damit wir ihn direkt erkennen! Da wir meist Texte mit mehreren Abs&auml;tzen haben, wollen wir au&szlig;erdem einstellen k&ouml;nnen, wie viele Abs&auml;tze vor und nach dem Absatz mit dem Suchbegriff ausgegeben werden sollen. <\/p>\n<p>Wir k&uuml;mmern uns zun&auml;chst um die einfache Variante der Prozedur, die nach dem Eingeben eines Suchbegriffs und dem Bet&auml;tigen der Taste <b>cmdSuchen <\/b>ausgel&ouml;st wird.<\/p>\n<h2>Tabelle zum Speichern der Fundstellen<\/h2>\n<p>Wenn wir einen oder mehrere l&auml;ngere Texte nach einem Suchbegriff durchsuchen, erhalten wir gegebenenfalls mehrere Suchergebnisse beziehungsweise Fundstellen. Um dem Benutzer diese anzuzeigen, speichern wir sie in einer Tabelle und geben den Inhalt der Tabelle dann in einem Formular aus. Die Tabelle zum Speichern der Fundstellen hei&szlig;t <b>tblFundstellen <\/b>und sieht im Entwurf wie in Bild 3 aus. Neben dem Prim&auml;rschl&uuml;sselfeld enth&auml;lt die Tabelle ein Feld zum Speichern der ID des Beitrags, aus dem die Fundstelle stammt, sowie die Fundstelle selbst.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_1119_003.png\" alt=\"Tabelle zum Speichern der Fundstellen\" width=\"499,6607\" height=\"358,0456\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Tabelle zum Speichern der Fundstellen<\/span><\/b><\/p>\n<p>Dabei soll es sich zun&auml;chst um die Zeile mit dem gefundenen Begriff und zur zus&auml;tzlichen Orientierung noch die vorherige und die folgende Zeile handeln.<\/p>\n<p>Da wir den Suchbegriff selbst in der Fundstelle als Richtext farbig markieren wollen, stellen wir f&uuml;r die Eigenschaft <b>Textformat <\/b>des Feldes <b>Fundstelle <\/b>den Wert <b>Rich-Text <\/b>ein.<\/p>\n<h2>Unterformular zur Anzeige der Fundstellen<\/h2>\n<p>Die Daten der Tabelle sollen in einem Unterformular namens <b>sfmVolltextsuche <\/b>ausgegeben werden. Dazu binden wir dieses Unterformular an die Tabelle <b>tblFundstellen <\/b>und ziehen das Feld <b>Fundstelle <\/b>aus der Feldliste in den Entwurf dieses Formulars (s. Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_1119_004.png\" alt=\"Entwurf des Unterformulars zur Anzeige der Fundstellen\" width=\"424,7115\" height=\"174,8813\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Entwurf des Unterformulars zur Anzeige der Fundstellen<\/span><\/b><\/p>\n<p>Da wir in dieses Unterformular weder Daten eingeben noch vorhandene Daten bearbeiten oder l&ouml;schen wollen, stellen wir die Eigenschaften <b>Anf&uuml;gen zulassen<\/b>, <b>L&ouml;schen zulassen <\/b>und <b>Bearbeiten zulassen <\/b>jeweils auf den Wert <b>Nein <\/b>ein.<\/p>\n<h2>Hauptformular mit der Suchfunktion<\/h2>\n<p>Das Hauptformular der L&ouml;sung enth&auml;lt die folgenden Steuer-elemente:<\/p>\n<ul>\n<li>Ein Textfeld namens <b>txtSuchbegriff <\/b>zur Eingabe des Suchbegriffs,<\/li>\n<li>eine Schaltfl&auml;che namens <b>cmdSuchen<\/b>, welche die Suche startet,<\/li>\n<li>das Unterformular <b>sfmVolltextsuche <\/b>und<\/li>\n<li>das MSForms-Textfeld <b>txtFundstelle<\/b>.<\/li>\n<\/ul>\n<p>Die Steuer-elemente werden wie in Bild 5 angeordnet. Damit die Suche nach der Eingabe des Suchbegriffs in das Textfeld <b>txtSuchbegriff <\/b>sowohl durch das Bet&auml;tigen der Eingabetaste als auch durch einen Mausklick auf die Schaltfl&auml;che <b>cmdSuchen <\/b>ausgel&ouml;st werden kann, stellen wir die Eigenschaft <b>Standard <\/b>der Schaltfl&auml;che <b>cmdSuchen <\/b>auf <b>Ja <\/b>ein.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_1119_005.png\" alt=\"Entwurf des Hauptformulars\" width=\"424,7115\" height=\"390,072\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Entwurf des Hauptformulars<\/span><\/b><\/p>\n<p>Damit das Unterformular mit den Suchstellen vergr&ouml;&szlig;ert wird, wenn der Benutzer das Hauptformular vergr&ouml;&szlig;ert, stellen wir die beiden Eigenschaften <b>Horizontaler Anker <\/b>und <b>Vertikaler Anker <\/b>jeweils auf den Wert <b>Beide <\/b>ein. Damit das Textfeld <b>txtFundstelle <\/b>nach unten verschoben wird, wenn der Benutzer die H&ouml;he des Formulars vergr&ouml;&szlig;ert, stellen wir die Eigenschaft <b>Vertikaler Anker <\/b>dieses Steuerelements auf den Wert <b>Unten <\/b>ein.<\/p>\n<p>Zieht der Benutzer das Formular in die Breite, soll auch das Textfeld verbreitert werden, also erh&auml;lt die Eigenschaft <b>Horizontaler Anker <\/b>den Wert <b>Beide<\/b>.<\/p>\n<p>Das Formular soll an die Tabelle mit den zu durchsuchenden Texten gebunden sein, damit sie den kompletten Text zur aktuell im Unterformular markierten Fundstelle schnell anzeigen kann.<\/p>\n<p>Deshalb stellen wir die Eigenschaft <b>Datenherkunft <\/b>des Formulars auf eine Abfrage namens <b>qryInhalt <\/b>ein, die wiederum folgenden SQL-Ausdruck enth&auml;lt und somit nur den Prim&auml;rschl&uuml;sselwert des betroffenen Beitrags sowie seinen vollst&auml;ndigen Text enth&auml;lt:<\/p>\n<pre>SELECT BeitragID, Inhalt, TextRoh\r\nFROM tblBeitraege;<\/pre>\n<p>Die MSForms-TextBox binden wir &uuml;ber die Eigenschaft <b>Steuerelementinhalt <\/b>an das Feld <b>Inhalt <\/b>dieser Abfrage.<\/p>\n<h2>Initialisieren des Formulars<\/h2>\n<p>Um das Formular und die Steuer-elemente zu initialisieren, legen wir zwei Ereignisprozeduren an. Die erste soll durch das Ereignis <b>Beim &ouml;ffnen <\/b>des Formulars ausgel&ouml;st werden und die gegebenenfalls noch vorhandenen Eintr&auml;ge in der Tabelle <b>tblFundstellen <\/b>l&ouml;schen.<\/p>\n<p>Diese Prozedur sieht wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Open(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     db.Execute \"DELETE FROM tblFundstellen\", dbFailOnError\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die zweite Prozedur l&ouml;st das Ereignis <b>Beim Laden <\/b>aus. Dort initialisieren wir eine Variable zum Referenzieren der MSForms-TextBox, die wie folgt deklariert wird:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>WithEvents objFundstelle<span style=\"color:blue;\"> As <\/span>MSForms.TextBox<\/pre>\n<p>Die durch das Ereignis <b>Beim Laden <\/b>ausgel&ouml;ste Prozedur hat folgenden Code:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Set<\/span> objFundstelle = Me!txtFundstelle.Object\r\n     <span style=\"color:blue;\">With<\/span> objFundstelle\r\n         .SelectionMargin = <span style=\"color:blue;\">False<\/span>\r\n         .Font = \"Calibri\"\r\n         .Font.Size = \"9\"\r\n         .MultiLine = <span style=\"color:blue;\">True<\/span>\r\n         .BorderStyle = fmBorderStyleSingle\r\n         .SpecialEffect = fmSpecialEffectFlat\r\n         .BorderColor = Me!txtSuchbegriff.BorderColor\r\n         .ScrollBars = fmScrollBarsVertical\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> sfm = Me!sfmVolltextsuche.Form\r\n     <span style=\"color:blue;\">With<\/span> sfm\r\n         .OnCurrent = \"[Event Procedure]\"\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Hier stellen wir vor allem die Eigenschaften der MSForms-TextBox <b>txtFundstelle <\/b>ein (Details siehe Beitrag <b>Die MSForms-TextBox<\/b>, <b>www.access-im-unternehmen.de\/1114<\/b>). Au&szlig;erdem referenzieren wir auch noch das Unterformular mit einer Variablen namens <b>sfm<\/b>. Auch diese soll im Kopf des Klassenmoduls deklariert werden, und zwar wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents sfm<span style=\"color:blue;\"> As <\/span>Form<\/pre>\n<p>Das Schl&uuml;sselwort <b>WithEvents <\/b>verwenden wir, weil wir im Hauptformular auf die Ereignisse des Unterformulars reagieren wollen, in diesem Fall auf das Ereignis <b>Beim Anzeigen<\/b>. Deshalb stellen wir die Eigenschaft <b>OnCurrent <\/b>von <b>sfm <\/b>auf den Wert <b>[Event Procedure] <\/b>ein. Die passende Ereignisprozedur k&ouml;nnen wir auch gleich vorstellen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>sfm_Current()\r\n     EintragAnzeigen\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die hier aufgerufene Prozedur <b>EintragAnzeigen <\/b>besprechen wir jedoch weiter unten.<\/p>\n<h2>Fundstellen ermitteln<\/h2>\n<p>Wenn der Benutzer einen Suchbegriff in das Textfeld <b>txtSuchbegriff <\/b>eingegeben hat und entweder die Eingabetaste bet&auml;tigt oder auf die Schaltfl&auml;che <b>cmdSuchen<\/b> klickt, l&ouml;st er damit die Ereignisprozedur <b>cmdSuchen_Click <\/b>aus, die Sie in Listing 1 finden.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdSuchen_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strSuche<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!txtSuchbegriff, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie einen Suchbegriff ein.\"\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     strSuche = Me!txtSuchbegriff\r\n     DoCmd.Hourglass <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM tblBeitraege WHERE TextRoh LIKE ''''*\" & strSuche & \"*''''\", dbOpenDynaset)\r\n     db.Execute \"DELETE FROM tblFundstellen\", dbFailOnError\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         TextDurchsuchen rst!TextRoh, strSuche, rst!BeitragID, db\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     Me!sfmVolltextsuche.Form.Requery\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> DCount(\"*\", \"tblFundstellen\") = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me.Filter = \"\"\r\n         EintragAnzeigen\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me!txtCode = Null\r\n         Me.Filter = \"1=2\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     Me.FilterOn = <span style=\"color:blue;\">True<\/span>\r\n     DoCmd.Hourglass <span style=\"color:blue;\">False<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Diese Prozedur wird beim Klick auf die Schaltfl&auml;che cmdSuchen ausgel&ouml;st.<\/span><\/b><\/p>\n<p>Diese Prozedur pr&uuml;ft zun&auml;chst, ob das Textfeld <b>txtSuchbegriff <\/b>&uuml;berhaupt einen Suchbegriff enth&auml;lt. Ist das nicht der Fall, erscheint eine entsprechende Meldung und die Prozedur wird beendet.<\/p>\n<p>Anderenfalls speichert die Prozedur den Suchbegriff aus dem Textfeld in der Variablen <b>strSuche <\/b>und aktiviert die Anzeige der Sanduhr. Dann f&uuml;llt sie die Variable <b>db <\/b>mit einem Verweis auf das aktuelle <b>Database<\/b>-Objekt. Die Variable <b>rst <\/b>erh&auml;lt ein Recordset, das alle Datens&auml;tze der Tabelle <b>tblBeitraege <\/b>enth&auml;lt, deren Feld <b>TextRoh <\/b>das Suchergebnis enth&auml;lt.<\/p>\n<p>Damit filtern wir alle Eintr&auml;ge der Tabelle heraus, die als Quelle f&uuml;r Fundstellen infrage kommen. Die folgende Anweisung l&ouml;scht dann alle gegebenenfalls noch vorhandenen Eintr&auml;ge der Tabelle <b>tblFundstellen<\/b>.<\/p>\n<p>Anschlie&szlig;end durchl&auml;uft die Prozedur alle Datens&auml;tze des Recordsets aus <b>rst<\/b>, also die Datens&auml;tze der Tabelle <b>tblBeitraege<\/b>, die den gesuchten Begriff enthalten.<\/p>\n<p>Dabei ruft sie f&uuml;r jeden Datensatz die Prozedur <b>TextDurchsuchen <\/b>auf und &uuml;bergibt den zu durchsuchenden Text, den Suchbegriff, die ID des Beitrags sowie einen Verweis auf das <b>Database<\/b>-Objekt der aktuellen Datenbank. Diese Prozedur schauen wir uns gleich im Detail an. Nur so viel: Sie durchsucht den kompletten Text nach Fundstellen und tr&auml;gt diese dann in die Tabelle <b>tblFundstellen <\/b>ein.<\/p>\n<p>Ist dies erledigt und die Tabelle <b>tblFundstellen <\/b>mit einigen Eintr&auml;gen gef&uuml;llt, wird das Unterformular, das ja an diese Tabelle gebunden ist, aktualisiert.<\/p>\n<p>Sollte keine Fundstelle vorhanden sein, wird der Filter des Hauptformulars &uuml;ber die Eigenschaft <b>Filter <\/b>auf <b>1=2 <\/b>eingestellt, was einem Filter entspricht, der keinen Datensatz zur&uuml;ckliefert. Wurden jedoch Eintr&auml;ge gefunden, wird der Filter geleert, sodass alle Eintr&auml;ge der zugrunde liegenden Tabelle &uuml;ber die Datenherkunft verf&uuml;gbar sind, und die Prozedur <b>EintragAnzeigen <\/b>aufgerufen. Auch diese schauen wir uns weiter unten an. Mit dem Ausblenden des Sanduhr-Symbols ist die Suche beendet.<\/p>\n<h2>Durchsuchen eines Beitrags<\/h2>\n<p>Die Prozedur <b>TextDurchsuchen <\/b>nimmt sich den in einem Datensatz der Tabelle <b>tblBeitraege <\/b>gespeicherten Text vor und durchsucht ihn nach allen Vorkommen des gesuchten Textes (s. Listing 2). Sie erwartet den Text (<b>strInhalt<\/b>), den Suchbegriff (<b>strSuche<\/b>), die ID des Datensatzes, aus dem der Inhalt stammt und einen Verweis auf das <b>Database<\/b>-Objekt der aktuellen Datenbank als Parameter.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>TextDurchsuchen(strInhalt<span style=\"color:blue;\"> As String<\/span>, strSuche<span style=\"color:blue;\"> As String<\/span>, lngBeitragID<span style=\"color:blue;\"> As Long<\/span>, db<span style=\"color:blue;\"> As <\/span>DAO.Database)\r\n     <span style=\"color:blue;\">Dim <\/span>bolErsteZeile<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngPosStart<span style=\"color:blue;\"> As Long<\/span>, lngPosEnde<span style=\"color:blue;\"> As Long<\/span>, lngStart<span style=\"color:blue;\"> As Long<\/span>, lngEnde<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strAusschnitt<span style=\"color:blue;\"> As String<\/span>, strSQL<span style=\"color:blue;\"> As String<\/span>\r\n     bolErsteZeile = <span style=\"color:blue;\">False<\/span>\r\n     lngPosStart = <span style=\"color:blue;\">InStr<\/span>(1, strInhalt, strSuche)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> lngPosStart = 0\r\n         lngStart = <span style=\"color:blue;\">InStrRev<\/span>(strInhalt, <span style=\"color:blue;\">vbCrLf<\/span>, lngPosStart)\r\n         <span style=\"color:blue;\">If <\/span>lngStart = 0<span style=\"color:blue;\"> Then<\/span>\r\n             lngStart = 1\r\n             bolErsteZeile = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             bolErsteZeile = <span style=\"color:blue;\">False<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         lngStart = <span style=\"color:blue;\">InStrRev<\/span>(strInhalt, <span style=\"color:blue;\">vbCrLf<\/span>, lngStart)\r\n         <span style=\"color:blue;\">If <\/span>lngStart = 0<span style=\"color:blue;\"> Then<\/span> bolErsteZeile = <span style=\"color:blue;\">True<\/span>\r\n         lngEnde = <span style=\"color:blue;\">InStr<\/span>(lngPosStart, strInhalt, <span style=\"color:blue;\">vbCrLf<\/span>)\r\n         lngEnde = <span style=\"color:blue;\">InStr<\/span>(lngEnde + 2, strInhalt, <span style=\"color:blue;\">vbCrLf<\/span>)\r\n         <span style=\"color:blue;\">If <\/span>lngEnde = 0<span style=\"color:blue;\"> Then<\/span>\r\n             lngEnde = <span style=\"color:blue;\">Len<\/span>(strInhalt)\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> bolErsteZeile<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span>lngEnde &gt; lngStart<span style=\"color:blue;\"> Then<\/span>\r\n                 strAusschnitt = <span style=\"color:blue;\">Mid<\/span>(strInhalt, lngStart + 2, lngEnde - lngStart - 2)\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 strAusschnitt = <span style=\"color:blue;\">Mid<\/span>(strInhalt, lngStart + 2)\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             strAusschnitt = <span style=\"color:blue;\">Mid<\/span>(strInhalt, lngStart + 1, lngEnde - lngStart - 1)\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         strAusschnitt = <span style=\"color:blue;\">Replace<\/span>(strAusschnitt, \"&lt;\", \"&lt;\")\r\n         strAusschnitt = <span style=\"color:blue;\">Replace<\/span>(strAusschnitt, \"&gt;\", \"&gt;\")\r\n         strAusschnitt = <span style=\"color:blue;\">Replace<\/span>(strAusschnitt, strSuche, \"&lt;font color=red&gt;\" & <span style=\"color:blue;\">Mid<\/span>(strInhalt, lngPosStart, _\r\n             <span style=\"color:blue;\">Len<\/span>(strSuche)) & \"&lt;\/font&gt;\")\r\n         strAusschnitt = <span style=\"color:blue;\">Replace<\/span>(strAusschnitt, \" &lt;font\", \" &lt;font\")\r\n         lngPosEnde = <span style=\"color:blue;\">InStr<\/span>(lngPosStart + 1, strInhalt, <span style=\"color:blue;\">vbCrLf<\/span>)\r\n         <span style=\"color:blue;\">If <\/span>lngPosEnde = 0<span style=\"color:blue;\"> Then<\/span>\r\n             lngPosEnde = <span style=\"color:blue;\">Len<\/span>(strInhalt)\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> bolErsteZeile<span style=\"color:blue;\"> Then<\/span>\r\n             lngPosStart = <span style=\"color:blue;\">InStr<\/span>(lngPosEnde + 1, strInhalt, strSuche)\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             lngPosStart = <span style=\"color:blue;\">InStr<\/span>(lngPosEnde + 1, strInhalt, strSuche) '''' + 1\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         strSQL = \"INSERT INTO tblFundstellen(BeitragID, Fundstelle) VALUES(\" & lngBeitragID & \", ''''\" _\r\n             & <span style=\"color:blue;\">Replace<\/span>(<span style=\"color:blue;\">Replace<\/span>(<span style=\"color:blue;\">Replace<\/span>(strAusschnitt, \"''''\", \"''''''''\"), <span style=\"color:blue;\">vbCrLf<\/span>, \"&lt;br&gt;\"), \"\"\"\", \"\"\"\"\"\") & \"'''')\"\r\n         db.Execute strSQL, dbFailOnError\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><!--30percent--><\/p>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Diese Prozedur ermittelt alle Vorkommen des Suchbegriffs.<\/span><\/b><\/p>\n<p>Die Prozedur stellt zun&auml;chst den Wert der Variablen <b>bol-ErsteZeile <\/b>auf den Wert <b>False <\/b>ein. Diese Variable gibt an, ob sich bereits in der ersten Zeile eine Fundstelle befindet &#8211; wir gehen davon aus, dass dies nicht der Fall ist. Dann ermittelt die folgende Anweisung mit der <b>InStr<\/b>-Funktion die tats&auml;chliche Position der ersten Fundstelle. Ist <b>lngPosStart<\/b>, also die Position der Fundstelle, ungleich <b>0<\/b>, steigt die Prozedur in eine <b>Do While<\/b>-Schleife ein, die solange l&auml;uft, bis keine weitere Fundstelle mehr gefunden werden kann, sprich: bis <b>lngPosStart <\/b>gleich <b>0 <\/b>ist.<\/p>\n<p>Ist also eine Fundstelle vorhanden, ermittelt die Prozedur zun&auml;chst die Position des letzten Zeilenumbruchs (<b>vbCrLf<\/b>) vor der Fundstelle. Befindet sich die Fundstelle also etwa irgendwo in der dritten Zeile des Textes aus <b>strInhalt<\/b>, dann sucht die Prozedur nun die Position des Starts der Zeile und tr&auml;gt die Position in die Variable <b>lngStart <\/b>ein.<\/p>\n<p>Die hier verwendete Funktion <b>InStrRev<\/b> erh&auml;lt den Inhalt von <b>strInhalt<\/b> als zu durchsuchenden Text, die Konstante f&uuml;r einen Zeilenumbruch zu suchende Zeichenfolge und die Position der aktuellen Fundstelle als Beginn der Suche.<\/p>\n<p>Diese l&auml;uft bei der Funktion <b>InStrRev<\/b> im Gegensatz zur Funktion <b>InStr <\/b>r&uuml;ckw&auml;rts, also in Richtung des Anfangs des Textes. Liefert <b>lngStart <\/b>den Wert <b>0<\/b>, befindet sich die Fundstelle tats&auml;chlich in der ersten Zeile. In diesem Falle wird <b>lngStart <\/b>auf <b>1 <\/b>eingestellt und <b>bolErsteZeile <\/b>erh&auml;lt den Wert <b>True<\/b>.<\/p>\n<p>In der aktuellen Version der Prozedur wollen wir immer die Zeile mit der Fundstelle, die Zeile davor und die Zeile danach als Fundstelle speichern. Wir haben nun in <b>lngStart <\/b>die Startposition der Zeile mit der Fundstelle gespeichert.<\/p>\n<p>Nun rufen wir erneut <b>InStrRev <\/b>auf, diesmal mit der Position aus <b>lngStart <\/b>als Startposition, und speichern die Position des letzten vor dieser Position befindlichen Zeilenumbruchs wieder in der Variablen <b>lngStart<\/b>. Wir springen also mit der in <b>lngStart<\/b> gespeicherten Position nicht an den Anfang der Zeile, in der sich der Suchbegriff befindet, sondern an den Anfang der vorherigen Zeile (sofern sich dort noch eine Zeile befindet).<\/p>\n<p>Danach ermitteln wir das Ende der Zeile, in der sich das Suchergebnis befindet, in dem wir mit der <b>InStr<\/b>-Funktion das n&auml;chste Vorkommen der Konstanten <b>vbCrLf <\/b>suchen und dessen Position in der Variablen <b>lngEnde <\/b>speichern.<\/p>\n<p>Dies wiederholen wir nochmals ab der Position, die sich zwei Zeichen hinter dieser Position befindet, und ermitteln so die Position des Endes der Zeile hinter der Zeile mit der Fundstelle.<\/p>\n<p>Auch hier kann es wieder sein, dass die Zeile mit der Fundstelle nicht mit einem Zeilenumbruch abgeschlossen wird &#8211; was bedeutet, dass die Zeile mit der Fundstelle die letzte Zeile in <b>strInhalt <\/b>ist.<\/p>\n<p>Nun kommt eine Fallunterscheidung, welchen Ausschnitt des Textes wir speichern wollen. Die erste <b>If&#8230;Then<\/b>-Bedingung pr&uuml;ft, ob sich die Fundstelle in der ersten Zeile befindet. Falls nicht, folgt eine weitere Fallunterscheidung &#8211; n&auml;mlich die, ob der Wert von <b>lngEnde <\/b>gr&ouml;&szlig;er ist als der von <b>lngStart<\/b>. Dies ist nur dann nicht der Fall, wenn <b>lngEnde <\/b>gleich <b>0 <\/b>ist, also die Zeile mit der Fundstelle die letzte Zeile in <b>strInhalt <\/b>ist. In diesem Fall liest die Prozedur den Bereich von der Position <b>lngStart + 2 <\/b>(also ohne das f&uuml;hrende <b>vbCrLf<\/b>) bis zur Position <b>lngEnde &#8211; 2 <\/b>(ohne das abschlie&szlig;ende <b>vbCrLf<\/b>) in die Variable <b>strAusschnitt <\/b>ein.<\/p>\n<p>Sollte <b>lngEnde <\/b>gleich <b>0 <\/b>sein und somit nicht gr&ouml;&szlig;er als <b>lngStart<\/b>, dann liest die Prozedur nur den Ausschnitt von der Position <b>lngStart + 2 <\/b>bis zum Ende von <b>strInhalt <\/b>in die Variable <b>strAusschnitt <\/b>ein. <\/p>\n<p>Fehlt noch der Fall, dass es sich bei der Zeile mit der Fundstelle um die erste Zeile handelt, also <b>bolErsteZeile <\/b>den Wert <b>True <\/b>enth&auml;lt: In diesem Fall liest die Prozedur den Text von der Startposition aus <b>lngStart + 1 <\/b>bis zur Endposition mit <b>lngEnde &#8211; 2 <\/b>in die Variable <b>strAusschnitt <\/b>ein.<\/p>\n<p>Danach ersetzt die Prozedur im Ausschnitt alle Kleiner- und Gr&ouml;&szlig;er-Zeichen durch entsprechende Escape-Sequenzen, also etwa <b>&lt; <\/b>oder <b>&gt;<\/b>, damit diese bei der Darstellung als Richtext korrekt interpretiert werden.<\/p>\n<h2>Markierung hinzuf&uuml;gen<\/h2>\n<p>Dann folgt eine wichtige Zeile: Diese ersetzt n&auml;mlich im Text aus <b>strAusschnitt<\/b> den gefundenen Inhalt durch den gleichen Inhalt, diesmal aber in die HTML-Auszeichnungen f&uuml;r die rote Textfarbe. Das sieht dann etwa so aus:<\/p>\n<pre>&lt;font color=red&gt;...&lt;\/font&gt;<\/pre>\n<p>Schlie&szlig;lich stellen wir diesem noch ein gesch&uuml;tztes Leerzeichen voran.<\/p>\n<p>Da es ja nicht nur eine Fundstelle im zu durchsuchenden Text geben kann, sondern mehrere, stellen wir nun die Position <b>lngPosEnde <\/b>auf das Ende der Zeile mit der Fundstelle ein und suchen von dort aus nach einem weiteren Vorkommen, dessen Start wir wieder in der Variablen <b>lngPosStart <\/b>speichern.<\/p>\n<p>Und damit schlie&szlig;t sich der Kreis praktisch, denn wenn <b>lngPosStart <\/b>dann wieder einen Wert ungleich <b>0 <\/b>enth&auml;lt und somit eine weitere Fundstelle vorliegt, wird die <b>Do While<\/b>-Schleife nochmals durchlaufen.<\/p>\n<p>Zuvor allerdings ist noch eine kleine Aufgabe zu erledigen: Die Fundstelle soll n&auml;mlich noch in der Tabelle <b>tbl-Fundstellen <\/b>gespeichert werden. Das erledigt dann eine <b>INSERT INTO<\/b>-Anweisung, die noch vor dem Durchlaufen der <b>Do While<\/b>-Schleife ausgef&uuml;hrt wird und den Inhalt von <b>strAusschnitt <\/b>speichert.<\/p>\n<p>Das Ergebnis sieht dann in der Tabelle <b>tblFundstellen <\/b>wie in Bild 6 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_1119_006.png\" alt=\"Die in der Tabelle tblFundstellen gespeicherten und farbig markierten Fundstellen\" width=\"700\" height=\"255,5859\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Die in der Tabelle tblFundstellen gespeicherten und farbig markierten Fundstellen<\/span><\/b><\/p>\n<p>Dass diese Liste auch noch im Unterformular erscheint, erledigt die Prozedur <b>cmdSuchen_Click<\/b>, die wir ja bereits weiter oben beschrieben haben.<\/p>\n<h2>Fundstelle im Kontext anzeigen<\/h2>\n<p>Nun wollen wir in dem Textfeld im unteren Bereich des Formulars den kompletten Text des Artikels anzeigen und dabei die Fundstelle erstens markierten und zweitens in den sichtbaren Bereich holen.<\/p>\n<p>Hier m&uuml;ssen wir uns wieder auf einen Kompromiss einigen: Wenn wir ein normales Textfeld verwenden, k&ouml;nnen wir durch die Einschr&auml;nkung der Funktion <b>SelStart <\/b>nur Fundstellen anzeigen, die sich in den ersten 32.767 Zeichen befinden. Das d&uuml;rfte bei Benutzer fr&uuml;her oder sp&auml;ter f&uuml;r Verwunderung sorgen. Also verwenden wir hier das <b>TextBox<\/b>-Steuerelement der MSForms-Bibliothek, das wir im Beitrag <b>Die MSForms-TextBox <\/b>(<b>www.access-im-unternehmen.de\/1114<\/b>) beschreiben.<\/p>\n<p>Der Nachteil der MSForms-TextBox ist wiederum, dass dieses keine Anzeige von Rich-Text erlaubt. Wir k&ouml;nnen also nicht die schicken roten Markierungen nutzen, die wir in der &uuml;bersicht der Fundstellen einsetzen. Also wollen wir die Fundstelle, die zum jeweils angeklickten Eintrag geh&ouml;ren, zumindest auf herk&ouml;mmliche Weise markieren, also mit dunkler Hintergrundfarbe.<\/p>\n<p>In unserem speziellen Fall arbeiten wir mit Texten, die im Original noch HTML-Auszeichnungen enthalten, die wir f&uuml;r die Anzeige der Suchergebnisse zun&auml;chst entfernen und denen wir dann zum Hervorheben der Suchergebnisse eigene HTML-Auszeichnungen hinzuf&uuml;gen.<\/p>\n<p>Da wir nun zur Anzeige der Fundstelle im Kontext des vollst&auml;ndigen Artikels nicht mehr die M&ouml;glichkeit haben, die HTML-Auszeichnung zu nutzen, m&uuml;ssen wir diese zun&auml;chst entfernen und dann die jeweilige Fundstelle hervorheben. Das wird insbesondere interessant, wenn ein Artikel mehrere Fundstellen aufweist. In diesem Fall haben wir nur die M&ouml;glichkeit, die Position der Fundstelle in der Liste der Suchergebnisse zu ermitteln und dann die entsprechende Position im gesamten Artikel zu suchen. Wenn das Datenblatt im oberen Bereich also etwa drei Eintr&auml;ge zu einem Artikel anzeigt und der Benutzer klickt den zweiten Eintrag an, dann soll das MSForms-Textfeld unten auch diesen zweiten Eintrag in den Fokus holen.<\/p>\n<p>Dazu f&uuml;gen wir der Tabelle <b>tblFundstellen <\/b>ein Feld namens <b>FundstelleIndex <\/b>mit dem Datentyp <b>Zahl <\/b>hinzu. Die Prozedur <b>TextDurchsuchen <\/b>haben wir dazu etwas angepasst &#8211; siehe Listing 3.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>TextDurchsuchen(...)\r\n     ...\r\n     <span style=\"color:blue;\">Dim <\/span>intFundstelleIndex<span style=\"color:blue;\"> As Integer<\/span>\r\n     ...\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> lngPosStart = 0\r\n         intFundstelleIndex = intFundstelleIndex + 1\r\n         ...\r\n         strSQL = \"INSERT INTO tblFundstellen(BeitragID, Fundstelle, FundstelleIndex) VALUES(\" & lngBeitragID & \", ''''\" _\r\n             & <span style=\"color:blue;\">Replace<\/span>(<span style=\"color:blue;\">Replace<\/span>(<span style=\"color:blue;\">Replace<\/span>(strAusschnitt, \"''''\", \"''''''''\"), <span style=\"color:blue;\">vbCrLf<\/span>, \"&lt;br&gt;\"), \"\"\"\", \"\"\"\"\"\") & \"'''', \" _\r\n             & intFundstelleIndex & \")\"\r\n         db.Execute strSQL, dbFailOnError\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Anpassung der Prozedur TextDurchsuchen zum Anlegen des Indexes einer Fundstelle<\/span><\/b><\/p>\n<h2>Auf Ereignisse im Unterformular reagieren<\/h2>\n<p>Damit wir im Klassenmodul des Hauptformulars die Ereignisse des Unterformulars implementieren k&ouml;nnen, haben wir, wie weiter oben bereits beschrieben, dort eine Variable angelegt, welche ein Formular mit dem Schl&uuml;sselwort <b>WithEvents <\/b>deklariert.<\/p>\n<p>Diese wird in der Ereignisprozedur <b>Form_Load <\/b>mit einem Verweis auf das im Unterformular-Steuerelement enthaltenen Formular gef&uuml;llt.<\/p>\n<p>Nun wollen wir das Ereignis <b>Beim Anzeigen <\/b>des Unterformulars im Klassenmodul des Hauptformulars implementieren, was wir wie folgt erledigen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>sfm_Current()\r\n     EintragAnzeigen\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Diese Prozedur l&ouml;st die Routine <b>EintragAnzeigen <\/b>aus Listing 4 aus. Die Prozedur deklariert einige Variablen und tr&auml;gt dann den Suchbegriff aus dem Textfeld <b>txtSuchbegriff <\/b>in die Variable <b>strSuchbegriff <\/b>ein.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>EintragAnzeigen()\r\n     <span style=\"color:blue;\">Dim <\/span>strInhalt<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strSuchbegriff<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngPosStart<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngLen<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>intIndex<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngCurLine<span style=\"color:blue;\"> As Long<\/span>\r\n     strSuche = Nz(Me!txtSuchbegriff)\r\n     intIndex = Me!sfmVolltextsuche.Form!FundstelleIndex\r\n     Me.Recordset.FindFirst \"BeitragID = \" & Me!sfmVolltextsuche.Form!BeitragID\r\n     strInhalt = Nz(Me!TextRoh)\r\n     strInhalt = <span style=\"color:blue;\">Replace<\/span>(strInhalt, \"&lt;b&gt;\", \"\")\r\n     strInhalt = <span style=\"color:blue;\">Replace<\/span>(strInhalt, \"&lt;\/b&gt;\", \"\")\r\n     Me!txtFundstelle = strInhalt\r\n     strSuchbegriff = Me!txtSuchbegriff\r\n     lng<span style=\"color:blue;\">Len<\/span> = <span style=\"color:blue;\">Len<\/span>(strSuchbegriff)\r\n     lngPosStart = <span style=\"color:blue;\">InStr<\/span>(1, strInhalt, strSuchbegriff)\r\n     For i = 2 To intIndex\r\n         lngPosStart = <span style=\"color:blue;\">InStr<\/span>(lngPosStart + lngLen, strInhalt, strSuchbegriff)\r\n     <span style=\"color:blue;\">Next<\/span> i\r\n     <span style=\"color:blue;\">With<\/span> objFundstelle\r\n         .CurLine = 0\r\n         .SelStart = lngPosStart\r\n         .SelLength = lngLen\r\n         lngCurLine = .CurLine\r\n         .CurLine = lngCurLine + 5\r\n         Me!txtFundstelle.SetFocus\r\n         .SelStart = lngPosStart\r\n         .SelLength = lngLen\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Anzeigen der aktuellen Fundstelle im Kontext des Artikels<\/span><\/b><\/p>\n<p>Dann lesen wir den Wert des Feldes <b>FundstelleIndex <\/b>des im Unterformular angeklickten Eintrags aus und schreiben ihn in die Variable <b>intIndex<\/b>. Die Prozedur stellt dann den Datensatzzeiger des Recordsets im Hauptformular, dass ja die Tabelle <b>tblBeitraege <\/b>enth&auml;lt, auf den Datensatz ein, zu dem die im Unterformular markierte Passage geh&ouml;rt. Der Inhalt aus dem Feld <b>TextRoh<\/b>, das den Text ohne HTML-Markierungen enth&auml;lt, landet in der Variablen <b>strInhalt<\/b>.<\/p>\n<p>Dort entfernen wir noch eventuell verbleibende Markierungen f&uuml;r fetten Schriftsatz. Danach landet der Text bereits im MSForms-Textfeld <b>txtFundstelle<\/b>. Nun ermitteln wir mit der <b>Len<\/b>-Funktion die L&auml;nge des Suchbegriffs aus der Variablen <b>strSuchbegriff <\/b>und speichern diese in <b>lngLen<\/b>. Die Variable <b>lngPosStat <\/b>soll hingegen die erste Position des Suchbegriffs im Text aus der Variablen <b>strInhalt <\/b>aufnehmen. Wir brauchen aber unter Umst&auml;nden nicht die erste Position, sondern eine Position mit einem anderen Index. Dieser Index steht in der Variablen <b>intIndex<\/b>. Wenn <b>intIndex <\/b>den Wert <b>1 <\/b>enth&auml;lt, haben wir die passende Position ja bereits gefunden. Anderenfalls durchlaufen wir nun in einer <b>For&#8230;Next<\/b>-Schleife alle Suchstellen bis zum gew&uuml;nschten Index, also vom Wert <b>2 <\/b>bis zum Wert von <b>intIndex<\/b>. Dabei f&uuml;llen wir <b>lngPosStart <\/b>jeweils mit der Position des Auftretens des Suchbegriffs, die dem Indexwert entspricht. Nach dem Verlassen der Schleife enth&auml;lt <b>lngPosStart <\/b>dann den gesuchten Wert.<\/p>\n<p>Damit brauchen wir nun nur noch die richtige Stelle im Text des MSForms-Textfeldes einzustellen, das wir mit <b>objFundstelle <\/b>referenziert haben. Dazu stellen wir zun&auml;chst die aktuelle Zeile auf die erste Zeile ein (<b>.CurLine = 0<\/b>), legen <b>SelStart<\/b> und <b>SelLength <\/b>auf die passenden Werte fest, ermitteln die Nummer der Zeile, welche die Markierung enth&auml;lt und stellen diese auf einen etwas gr&ouml;&szlig;eren Wert ein, damit die Markierung nicht ganz unten im Textfeld erscheint (<b>.CurLine = lngCurLine + 5<\/b>). Dann m&uuml;ssen wir den Fokus auf das Textfeld einstellen und die Markierung erneut setzen, damit diese sichtbar wird.<\/p>\n<p>Das Ergebnis stimmt fast, aber leider nicht ganz: Offensichtlich verschiebt sich die Markierung, je weiter unten das Suchergebnis liegt, um Vielfache von zwei nach hinten (s. Bild 7). Au&szlig;erdem werden Suchergebnisse, die &uuml;ber einem bereits einmal aufgerufenen Suchergebnis liegen, merkw&uuml;rdigerweise nicht mehr markiert, sondern nur noch angezeigt. Das verlangt nach Untersuchung und Nacharbeit. Was die Verschiebung angeht, sind zwei Faktoren schuld: Der erste ist, dass die <b>InStr<\/b>-Funktion einen 1-basierten Wert liefert, die <b>SelStart<\/b>-Eigenschaft des Textfeldes jedoch einen 0-basierten Wert erwartet.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_1119_007.png\" alt=\"Die Markierung der Fundstelle ist leicht verschoben.\" width=\"499,6607\" height=\"423,4874\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Die Markierung der Fundstelle ist leicht verschoben.<\/span><\/b><\/p>\n<p>Das hei&szlig;t, dass die Markierung grunds&auml;tzlich schon einmal um eins nach rechts verschoben wird. Die andere Verschiebung, die umso gr&ouml;&szlig;er wird, je weiter unten sich der Suchbegriff befindet, ist durch eine unterschiedliche Ber&uuml;cksichtigung des Zeilenumbruch-Zeichens zu erkl&auml;ren. Die <b>InStr<\/b>-Funktion interpretiert den Zeilenumbruch als zwei Zeichen (<b>vbCrLf <\/b>beziehungsweise <b>Chr(13) &#038; Chr(10)<\/b>, die <b>SelStart<\/b>-Eigenschaft jedoch als ein Zeichen (nur <b>Chr(13)<\/b>). Also m&uuml;ssen wir einen Korrekturfaktor hinzuziehen, welcher die L&auml;nge des Textes bis zum Beginn der Fundstelle ermittelt, die Anzahl der Zeilenumbr&uuml;che bis dazu z&auml;hlt und f&uuml;r jeden Zeilenumbruch den Wert 1 ber&uuml;cksichtigt.<\/p>\n<p>Das erledigen wir, indem wir <b>lngPosStart <\/b>f&uuml;r die Anzahl der Zeichen bis zum Beginn der Fundstelle hinzuziehen und dann die L&auml;nge der Zeichenkette bis zu dieser Stelle, bei der wir die Zeilenumbr&uuml;che durch leere Zeichenketten ersetzt haben, abziehen. Diesen Wert teilen wir dann noch durch zwei, da wir ja f&uuml;r jeden Zeilenumbruch nur ein Zeichen weniger berechnen m&uuml;ssen (<b>Chr(13) <\/b>statt <b>Chr(13) &#038; Chr(10)<\/b>). Au&szlig;erdem ziehen wir noch den Wert <b>1 <\/b>von <b>lngPosStart <\/b>als zus&auml;tzlichen Korrekturfaktor f&uuml;r die unterschiedliche Basis von <b>InStr <\/b>und <b>SelStart <\/b>ab, was dann wie folgt aussieht:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>EintragAnzeigen()\r\n     <span style=\"color:blue;\">Dim <\/span>intDiff<span style=\"color:blue;\"> As Integer<\/span>\r\n     ...\r\n     intDiff = (lngPosStart - <span style=\"color:blue;\">Len<\/span>(<span style=\"color:blue;\">Replace<\/span>(<span style=\"color:blue;\">Left<\/span>(strInhalt, _\r\n         lngPosStart), <span style=\"color:blue;\">vbCrLf<\/span>, \"\"))) \/ 2\r\n     <span style=\"color:blue;\">With<\/span> objFundstelle\r\n         .CurLine = 0\r\n         .SelStart = lngPosStart - 1 - intDiff\r\n         ...\r\n         .SelStart = lngPosStart - 1 - intDiff\r\n         .SelLength = lngLen\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Warum aber werden die Fundstellen, die sich oberhalb der untersten bisher markierten Fundstelle befinden, nicht mehr wie gew&uuml;nscht markiert &#8211; wohl aber an der korrekten Stelle eingeblendet<\/p>\n<p>Eine weitere Untersuchung ergab auch, dass nach dem einmaligen Scheitern der Markierung des Suchergebnisses durch ein erneutes Ausw&auml;hlen einer weiter oben liegenden Fundstelle manchmal &uuml;berhaupt keine Markierungen mehr gesetzt werden konnten. Wo liegt das Problem Durch Zufall kam heraus, dass es sich um Problem des Fokus handelt und die Markierung nicht angezeigt wird, weil das Steuer-element schlicht nicht den Fokus hat.<\/p>\n<p>Das ist aufgefallen, als wir zwischendurch zum VBA-Editor und wieder zur&uuml;ck zum VBA-Fenstern gewechselt sind &#8211; pl&ouml;tzlich war die Markierung sichtbar. Es zeigt sich, dass wir dieses Problem durch eine einfache Eigenschaftseinstellung beheben k&ouml;nnen &#8211; und zwar direkt beim Laden des Formulars. Dazu passen wir die Ereignisprozedur, die durch das Ereignis <b>Beim Laden <\/b>ausgel&ouml;st wird, wie folgt an:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Set<\/span> objFundstelle = Me!txtFundstelle.Object\r\n     <span style=\"color:blue;\">With<\/span> objFundstelle\r\n         ...\r\n         .HideSelection = <span style=\"color:blue;\">False<\/span>\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Wir stellen also schlicht die Eigenschaft <b>HideSelection <\/b>auf den Wert <b>False <\/b>ein, was daf&uuml;r sorgt, dass die aktuelle Markierung beim Fokusverlust nicht ausgeblendet wird. Damit erscheint die Fundstelle nun in allen F&auml;llen mit korrekter Markierung (s. Bild 8).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_1119_008.png\" alt=\"Nun passt die Markierung der Fundstellen.\" width=\"499,6607\" height=\"423,4874\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Nun passt die Markierung der Fundstellen.<\/span><\/b><\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Mit dieser L&ouml;sung erhalten Sie eine praktische Suchfunktion, mit der Sie auch gr&ouml;&szlig;ere Texte komfortabel auf die gew&uuml;nschten Suchbegriffe hin untersuchen k&ouml;nnen. F&uuml;r den Einsatz in eigenen Anwendungen passen Sie die Abfrage <b>qryInhalt<\/b> so an, dass das Feld <b>InhaltRoh<\/b> der Abfrage auf den unformatierten Inhalt des zu durchsuchenden Textes liefert. In der Beispieldatenbank haben wir dazu den als HTML formatierten Text &uuml;ber die Hilfsprozedur <b>RohtextErstellen<\/b>, welche die HTML-Formatierungen aus den Texten entfernte, in ein neues Feld der Tabelle der Inhalte geschrieben. Diese Prozedur, die Sie in Listing 5 sehen, durchl&auml;uft alle Datens&auml;tze der Tabelle <b>tblBeitraege <\/b>und speichert den Inhalt des Feldes <b>Inhalt <\/b>jeweils in der Variablen <b>strTemp<\/b>. Aus dieser entfernt sie mit der <b>Replace<\/b>-Funktion jeweils die HTML-Tags und ersetzt diese bei &ouml;ffnenden Text durch leere Zeichenketten und bei schlie&szlig;enden Tags, die einen Zeilenumbruch beinhalten, mit einm Zeilenumbruch (<b>vbCrLf<\/b>). Das Ergebnis speichert die Prozedur dann im Feld <b>TextRoh <\/b>der Tabelle <b>tblBeitraege <\/b>und speichert dann den Datensatz &#8211; dies nur als Erg&auml;nzung, falls Ihre Texte gegebenenfalls als HTML- oder Access-Richtext formatiert sind.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>RohtextErstellen()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strTemp<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM tblBeitraege\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         strTemp = Nz(rst!Inhalt)\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;p&gt;\", \"\")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;h1&gt;\", \"\")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;li&gt;\", \"\")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;pre&gt;\", \"\")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;p class=\"\"tabelleungerade\"\"&gt;\", \"\")\r\n         ...\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;span class=\"\"kursiv\"\"&gt;\", \"\")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;\/span\", \"\")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \" (\" & <span style=\"color:blue;\">vbCrLf<\/span>, \"|\")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;\/h1&gt;\", <span style=\"color:blue;\">vbCrLf<\/span>)\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;\/p&gt;\", <span style=\"color:blue;\">vbCrLf<\/span>)\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;\/li&gt;\", <span style=\"color:blue;\">vbCrLf<\/span>)\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;\/pre&gt;\", <span style=\"color:blue;\">vbCrLf<\/span>)\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, <span style=\"color:blue;\">vbCrLf<\/span> & \"&lt;\/b&gt;\", \"&lt;\/b&gt;\")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&ouml;\", \"&ouml;\")\r\n         ...\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \" \", \" \")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span>, <span style=\"color:blue;\">vbCrLf<\/span>)\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;font color=blue&gt;\", \"\")\r\n         strTemp = <span style=\"color:blue;\">Replace<\/span>(strTemp, \"&lt;\/font&gt;\", \"\")\r\n         rst.Edit\r\n         rst!TextRoh = strTemp\r\n         rst.Update\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Umwandeln eines mit HTML-Elementen ausgezeichneten Textes in einen Text ohne HTML-Tags<\/span><\/b><\/p>\n<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>VolltextsucheMitFundstellen.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/30C49FDF-0C51-480A-9E12-6CA6A8F3B01A\/aiu_1119.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Neulich wollte ich mal meine Artikeldatenbank nach bestimmten Suchbegriffen durchforsten. Also habe ich mir eine Abfrage gebaut, die nur die relevanten Felder der zu durchsuchenden Tabelle enth&auml;lt. Dort dachte ich dann, ich k&ouml;nnte mit der eingebauten Filter-Funktion des Datenblatts schnell zu den gesuchten Fundstellen gelangen. Das Ergebnis war ern&uuml;chternd, denn Access lieferte zwar alle passenden Datens&auml;tze, aber in den recht langen Texten innerhalb der Datens&auml;tze musste ich dann nochmals nach dem gesuchten Text suchen. Das konnte ich nicht auf mir sitzen lassen und habe eine Suchfunktion mit Fundstellen programmiert, die dieser Beitrag vorstellt.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66012018,662018,44000027],"tags":[],"class_list":["post-55001119","post","type-post","status-publish","format-standard","hentry","category-66012018","category-662018","category-Loesungen"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Volltextsuche mit Fundstellen - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Volltextsuche mit Fundstellen\" \/>\n<meta property=\"og:description\" content=\"Neulich wollte ich mal meine Artikeldatenbank nach bestimmten Suchbegriffen durchforsten. Also habe ich mir eine Abfrage gebaut, die nur die relevanten Felder der zu durchsuchenden Tabelle enth&auml;lt. Dort dachte ich dann, ich k&ouml;nnte mit der eingebauten Filter-Funktion des Datenblatts schnell zu den gesuchten Fundstellen gelangen. Das Ergebnis war ern&uuml;chternd, denn Access lieferte zwar alle passenden Datens&auml;tze, aber in den recht langen Texten innerhalb der Datens&auml;tze musste ich dann nochmals nach dem gesuchten Text suchen. Das konnte ich nicht auf mir sitzen lassen und habe eine Suchfunktion mit Fundstellen programmiert, die dieser Beitrag vorstellt.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-08T18:32:33+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg06.met.vgwort.de\/na\/5069ba44aae74c40a54f1cbd9128f3e7\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"24\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Volltextsuche mit Fundstellen\",\"datePublished\":\"2022-03-08T18:32:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/\"},\"wordCount\":3960,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/5069ba44aae74c40a54f1cbd9128f3e7\",\"articleSection\":[\"1\\\/2018\",\"2018\",\"L\u00f6sungen\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/\",\"name\":\"Volltextsuche mit Fundstellen - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/5069ba44aae74c40a54f1cbd9128f3e7\",\"datePublished\":\"2022-03-08T18:32:33+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/5069ba44aae74c40a54f1cbd9128f3e7\",\"contentUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/5069ba44aae74c40a54f1cbd9128f3e7\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Volltextsuche_mit_Fundstellen\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Volltextsuche mit Fundstellen\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Volltextsuche mit Fundstellen - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/","og_locale":"de_DE","og_type":"article","og_title":"Volltextsuche mit Fundstellen","og_description":"Neulich wollte ich mal meine Artikeldatenbank nach bestimmten Suchbegriffen durchforsten. Also habe ich mir eine Abfrage gebaut, die nur die relevanten Felder der zu durchsuchenden Tabelle enth&auml;lt. Dort dachte ich dann, ich k&ouml;nnte mit der eingebauten Filter-Funktion des Datenblatts schnell zu den gesuchten Fundstellen gelangen. Das Ergebnis war ern&uuml;chternd, denn Access lieferte zwar alle passenden Datens&auml;tze, aber in den recht langen Texten innerhalb der Datens&auml;tze musste ich dann nochmals nach dem gesuchten Text suchen. Das konnte ich nicht auf mir sitzen lassen und habe eine Suchfunktion mit Fundstellen programmiert, die dieser Beitrag vorstellt.","og_url":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/","og_site_name":"Access im Unternehmen","article_published_time":"2022-03-08T18:32:33+00:00","og_image":[{"url":"http:\/\/vg06.met.vgwort.de\/na\/5069ba44aae74c40a54f1cbd9128f3e7","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"24\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Volltextsuche mit Fundstellen","datePublished":"2022-03-08T18:32:33+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/"},"wordCount":3960,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/5069ba44aae74c40a54f1cbd9128f3e7","articleSection":["1\/2018","2018","L\u00f6sungen"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/","url":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/","name":"Volltextsuche mit Fundstellen - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/5069ba44aae74c40a54f1cbd9128f3e7","datePublished":"2022-03-08T18:32:33+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/#primaryimage","url":"http:\/\/vg06.met.vgwort.de\/na\/5069ba44aae74c40a54f1cbd9128f3e7","contentUrl":"http:\/\/vg06.met.vgwort.de\/na\/5069ba44aae74c40a54f1cbd9128f3e7"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Volltextsuche_mit_Fundstellen\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Volltextsuche mit Fundstellen"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001119","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001119"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001119\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001119"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001119"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001119"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}