Top-Themen

AppleEntwicklungHardwareInternetLinuxMicrosoftMultimediaNetzwerkeOff TopicSicherheitSonstige SystemeVirtualisierungWeiterbildungZusammenarbeit

Aktuelle Themen

Administrator.de FeedbackApache ServerAppleAssemblerAudioAusbildungAuslandBackupBasicBatch & ShellBenchmarksBibliotheken & ToolkitsBlogsCloud-DiensteClusterCMSCPU, RAM, MainboardsCSSC und C++DatenbankenDatenschutzDebianDigitiales FernsehenDNSDrucker und ScannerDSL, VDSLE-BooksE-BusinessE-MailEntwicklungErkennung und -AbwehrExchange ServerFestplatten, SSD, RaidFirewallFlatratesGoogle AndroidGrafikGrafikkarten & MonitoreGroupwareHardwareHosting & HousingHTMLHumor (lol)Hyper-VIconsIDE & EditorenInformationsdiensteInstallationInstant MessagingInternetInternet DomäneniOSISDN & AnaloganschlüsseiTunesJavaJavaScriptKiXtartKVMLAN, WAN, WirelessLinuxLinux DesktopLinux NetzwerkLinux ToolsLinux UserverwaltungLizenzierungMac OS XMicrosoftMicrosoft OfficeMikroTik RouterOSMonitoringMultimediaMultimedia & ZubehörNetzwerkeNetzwerkgrundlagenNetzwerkmanagementNetzwerkprotokolleNotebook & ZubehörNovell NetwareOff TopicOpenOffice, LibreOfficeOutlook & MailPapierkorbPascal und DelphiPeripheriegerätePerlPHPPythonRechtliche FragenRedHat, CentOS, FedoraRouter & RoutingSambaSAN, NAS, DASSchriftartenSchulung & TrainingSEOServerServer-HardwareSicherheitSicherheits-ToolsSicherheitsgrundlagenSolarisSonstige SystemeSoziale NetzwerkeSpeicherkartenStudentenjobs & PraktikumSuche ProjektpartnerSuseSwitche und HubsTipps & TricksTK-Netze & GeräteUbuntuUMTS, EDGE & GPRSUtilitiesVB for ApplicationsVerschlüsselung & ZertifikateVideo & StreamingViren und TrojanerVirtualisierungVisual StudioVmwareVoice over IPWebbrowserWebentwicklungWeiterbildungWindows 7Windows 8Windows 10Windows InstallationWindows MobileWindows NetzwerkWindows ServerWindows SystemdateienWindows ToolsWindows UpdateWindows UserverwaltungWindows VistaWindows XPXenserverXMLZusammenarbeit
GELÖST

PHP Glossar-Parser Herausforderung für Profis

Frage Entwicklung PHP

Mitglied: Frank

Frank (Level 5) - Jetzt verbinden

12.06.2008, aktualisiert 28.12.2012, 7567 Aufrufe, 10 Kommentare

Euer Webmaster braucht mal ein wenig Hilfe

Hi, heute habe ich mal eine kleine Aufgabe für PHP Profis.
Für unser Glossar auf administrator.de brauche ich einen performanten Glossar-Parser.

Folgendes Szenario bzw. Variablen bestehen (vereinfacht):

01.
$content = "Das ist jetzt der Text der Mitglieder mit Glossar-Begriffen wie Server oder Internet. Umlaute wie &ouml; oder &szlig; sind mit htmlentities umgewandelt. Das TCP/IP Protokoll oder den Begriff Firewall sollen mit einem Glossar-Link markiert werden. Der Text hat aber auch <a href=\"/index.php?content=Serverprobleme_im_Internet.html\" titel=\"Server und Internet Probleme\">Links</a> oder Images <img src=\"/images/articles/server.jpg\" alt=\"\" /> die nicht interpretiert werden dürfen."
02.
 
03.
$glossar_arr = array(array("Internet","2"), array("Server","3"), array("Firewall","4"), array("TCP/IP","5"), array("etc.","id"));
$content
Die Inhalte von "$content" liegt im "htmlentities($content, ENT_QUOTES);" Format vor (aus Sicherheitsgründen, damit kein HTML interpretiert wird). Die HTML-Tags wie <img.. > oder <a href..> kommen zunächst von unserem Format-Parser. Danach soll der Glossar-Parser starten. Er darf HTML-Tags also nicht berücksichtigen. Die Variable "$content" kann bis zu 10.000 Wörter fassen.

$glossar_arr
Das Array "$glossar_arr" kann aus mehr als 10.000 Begriffen bestehen. Der erste Wert ist der Glossar-Begriff, der zweite die ID. Der Glossar-Link zum Aufruf lautet dann z.B.: /index.php?mod=glossar&idx=2

Ich suche jetzt eine Abfrage, eine RegExp oder sonstige PHP Lösung, die sehr performant den Inhalt in "$content" durchsucht und die zutreffenden Glossar-Begriffe aus dem Array (wie im Beispiel "Internet", "Server", etc.) mit dem Link markiert bzw. den Begriff durch den Link plus Begriff ersetzt.

Natürlich dürfen die HTML-Tags wie <img ..> oder <a href..> nicht berücksichtigt werden (z.B. darf im Link "title="-Tag der Glossar-Parser nicht greifen, am besten alle HTML-Tags excluden). Auch sollen nur ganze Wörter und keine Teilbegriffe gefunden werden.

Für eine Lösung wäre ich sehr dankbar

P.S. Ich poste meine bisherige Lösung extra nicht, um neue Ideen und einen neuen Ansatz zu finden. Meine Lösung ist bisher zu langsam.

Gruß
Frank
Webmaster
Mitglied: masterG
LÖSUNG 12.06.2008, aktualisiert 05.12.2013
Hallo Frank!
Hast du schon mit preg_replace bzw. str_replace ausprobiert?
Also dass es z.B. so aussehen könnte:
01.
<?php 
02.
$content = str_replace("Internet","<a href="glossar.php">Internet</a>", $content); 
03.
?>
Auch eine Lösung wär auch das du das mit einer while funktion machst:
01.
<?php 
02.
mysql_connect("localhost","root",""); 
03.
mysql_select_db("db"); 
04.
$sql = "SELECT ID, titel FROM glossar;"
05.
$result = mysql_query($sql); 
06.
while($row = mysql_fetch_array($result) or die(mysql_error())) 
07.
08.
$content = str_replace($row['titel'],"<a href=glossar.php?idx=".$row['ID'].">".$row['titel']."</a>", $content); 
09.
10.
?>
mfg
masterG
Bitte warten ..
Mitglied: Frank
12.06.2008 um 15:32 Uhr
Hi masterG,

nicht ganz

a) Bei den HTML-Tags wie z.B.
01.
.. text text <a href="/Internet.html" title="Das ist der Internet Testbeitrag">Internet Link</a> text text ...
in "$content" hättest Du mit Deiner Lösung ein großes Problem. Das gilt auch für Bilder mit "alt=" oder "title=" Tag. Die HTML-Tags dürfen nicht mit durchsucht werden.

b) Bei einem Glossar von 10.000 Begriffen und einem Text von 5000 Wörtern in "$content" hättest Du mir Deiner DB-Lösung ein sehr großes Performance Problem.

Es muss eine Lösung OHNE Datenbank sein (bitte beachtet nur das Array $glossar_arr und die Variable $content). Es sieht leicht aus, ist es aber nicht.

Bitte validiert bzw. testet Euren Quellcode mit den Variablen $content und dem Array $glossar_arr vom Beitrag oben. Es sollte schon etwas konkreter sein.

Gruß
Frank
Bitte warten ..
Mitglied: Dani
12.06.2008 um 16:07 Uhr
Hi Frank,
wie hast du es mit den Formatierungsmöglichkeiten gelöst?! Da wirst du doch auch sicher REGEX verwendet haben, oder?

Ansonsten gehen mir 2 Ideen gerade durch den Kopf (erfährst du später mehr)....mit was ich mir ein bisschen schwer tu, ist der Faktor "Leistungsaufwand der MySQL". Wie hälst du die 10.000 Begriffe immer im PHP? Hast du ne $_SESSION Array gebildet oder wie darf ich mir das vorstellen. Denn wir reden hier ja grad nicht über ne 0815 Datenbank.


Gruss,
Dani
Bitte warten ..
Mitglied: Frank
12.06.2008 um 16:31 Uhr
Hi Dani,

Die Datenbank für den Glossar ist komplett im Arbeitsspeicher (ich sag mal RamDisk, MySQL hat einen Tabellentyp: MEMORY). Also habe ich alle 10.000 Begriffe in dem Array wie oben beschrieben. Darüber braucht man sich also keinen Kopf zu zerbrechen.

Es geht hier nur um eine schnelle Funktion dieses gesamte Array ($glossar_arr) jetzt gegen einen Text ($content) abzugleichen, dabei aber die vorhandenen HTML-Tags nicht zu berücksichtigen (und das sehr performant).

wie hast du es mit den Formatierungsmöglichkeiten gelöst?! Da wirst du doch auch sicher REGEX verwendet
haben, oder?

Ja, im Format-Parser benutze ich RegExp. Aber auch da habe ich Probleme bei manchen HTML-Tags Kombinationen die ich dann (ich sag mal "dirty") abfange. Daher brauche ich einen neuen Ansatz.

Gruß
Frank
Bitte warten ..
Mitglied: 16568
LÖSUNG 12.06.2008, aktualisiert 05.12.2013
Ich verstehe den aktuellen Zustand sehr wohl, jedoch würde ich zu einer anderen Lösung ansetzen.

Anstelle die Glossar-Links jedesmal on-the-fly zu generieren, würde ich diese bereits beim in-die-Datenbank-schreiben setzen lassen.
Hat einzig und alleine den Nachteil, daß wenn ein Begriff wegfällt, die ganze DB aktualisiert werden müßte.
(ob dies jemals vorkommt, weiß ich allerdings nicht...)

Der Regex ist sicherlich ein wenig komplexer, aber ich denke, Du wirst mit Sicherheit schon den performantesten haben.
Regex bedeutet immer rechenintensiv, weil er ausgewertet werden muß.
Die o.g. Lösung wird einfach nur ausgespuckt, und auch die Aktualisierung der DB liese sich in 1-2 Tagen komplett realisieren


Lonesome Walker
Bitte warten ..
Mitglied: filippg
12.06.2008 um 21:57 Uhr
Hallo,

ich möchte ja jetzt nicht als Miesepeter dastehen. Aber ich würde empfehlen, das Problem durch Verzicht auf das Glossar zu lösen.
Brauchen wir hier wirklich einen Link, der uns erklärt, was ein "Server" oder eine "Firewall" ist? Und wenn es um "schwierigere" Begriffe geht ist ein Glossar m.E. nach sowieso schnell am Ende. Solche Begriffe bedürfen dann auch meist keiner allgemeinen Erklärung sondern sind oft Kontextabhängig (oder halt sehr umständlich zu erklären).
Vorschlag für eine Alternative: eine Funktion, mit der man ein Wort markieren und dann mit einem Mausklick in einer gängigen Suchmaschine suchen kann.

Gruß

Filipp
Bitte warten ..
Mitglied: Frank
13.06.2008 um 10:04 Uhr
Hi Lonesome Walker,

klar, ich kann das auch schon vorher (z.B. per Scriptlauf) in die Datenbank schreiben anstatt es "onthefly" zu machen.
Trotzdem brauche ich auch dafür die Funktion das gesamte Array ($glossar_arr) gegen den Text ($content) abzugleichen und dabei die vorhandenen HTML-Tags nicht zu berücksichtigen. Gut, dass muss zwar dann nicht mehr so peformant sein, aber schnell muss es trotzdem gehen. Sonst würde das Script bei der Masse an Beiträge und Kommentare zu lange laufen.

Also bitte nur auf diese Funktion konzentrieren und nicht dem drumherum!

Vielleicht jetzt noch mal etwas einfacher: Ich suche eine schnelle RegExp-Lösung die eine Array als Suchfeld benutzt und bei dem durchsuchenden Text die HTML-Tags nicht berücksichtigt. Es muss auch nicht zwingend reines RexExp sein, es kann z.B. auch eine Array- oder "sonstwas" Lösung sein. Das Problem liegt ganz klar bei den HTML-Tags. Die nicht zu berücksichtigen ist mein Hauptproblem.

Also vergesst bitte die DB, vergesst die Art wie es angezeigt wird (vorberechnet oder "onthefly") und stellt bitte keine Aussagen über den Sinn- oder Unsinn eines Glossar hier rein. Nur die Funktion ist wichtig.

Hier ein möglicher Befehl: "preg_replace" oder "preg_replace_callback". Kennt sich damit einer sehr gut aus?
Gibt es denn keine PHP oder RegExp Profis mehr?

Gruß
Frank
Webmaster
Bitte warten ..
Mitglied: Frank
13.06.2008 um 10:09 Uhr
Hallo Filipp,

"Server" oder "Firewall" sind hier nur einfache Beispiele.

Und wenn es um "schwierigere" Begriffe geht ist ein Glossar m.E. nach sowieso schnell am Ende.
Da wäre es doch schön wenn wir es später besser machen würden.

Vorschlag für eine Alternative: eine Funktion, mit der man ein Wort markieren und dann mit einem Mausklick in einer gängigen
Suchmaschine suchen kann.
Mein Safari-Browser kann das jetzt schon und mit dem Firefox wird es auch bald gehen. Das ist keine Funktion die von uns kommen kann, immer nur vom Browser. Über den Sinn- oder Unsinn des Glossars will ich hier aber jetzt nicht diskutieren. Nur weil wir bisher keine gute Lösung gefunden haben, heiß es nicht das es sie nicht gibt.
Also bitte keine Kommentare mehr in diese Richtung, die lösche ich dann sofort.

Gruß
Frank
Bitte warten ..
Mitglied: Frank
13.06.2008, aktualisiert 06.01.2015
Hi,

nach dem da ja nix wirklich sinnvolles kam, hier mal mein neuer Ansatz:

01.
<? 
02.
// --------------------------- 
03.
// GLOSSAR-PARSER Version: 2.0 
04.
// --------------------------- 
05.
 
06.
// CONTENT 
07.
 
08.
$content = "Das ist jetzt der Text der Mitglieder mit Glossar-Begriffen wie Server oder Internet. Umlaute wie &ouml; oder &szlig; sind mit htmlentities umgewandelt. Das TCP/IP Protokoll oder den Begriff Firewall sollen mit einem Glossar-Link markiert werden. Der Text hat aber auch <a href=\"/index.php?content=Serverprobleme_im_Internet.html\" title=\"Server und Internet Probleme\">Links</a> oder Images <img src=\"/images/icons/16x16/filesystems/folder_home.gif\" alt=\"Das Internet und die Server\" title=\"Server und Internet Probleme\"/> die nicht interpretiert werden dürfen. ACL aber schon."
09.
 
10.
// INIT GLOSSAR ARRAY 
11.
// Beispiel-Daten 
12.
 
13.
$glossar_search_arr[0]='/Internet\b/i'
14.
$glossar_search_arr[1]='/Server\b/i'
15.
$glossar_search_arr[2]='/Firewall\b/i'
16.
$glossar_search_arr[3]='/TCP\/IP\b/i'
17.
$glossar_search_arr[4]='/ACL\b/i'
18.
 
19.
$glossar_replace_arr[0]='<a href="/index.php?mod=glossar&idx=1">Internet</a>'
20.
$glossar_replace_arr[1]='<a href="/index.php?mod=glossar&idx=3">Server</a>'
21.
$glossar_replace_arr[2]='<a href="/index.php?mod=glossar&idx=4">Firewall</a>'
22.
$glossar_replace_arr[3]='<a href="/index.php?mod=glossar&idx=5">TCP/IP</a>'
23.
$glossar_replace_arr[4]='<a href="/index.php?mod=glossar&idx=2">ACL</a>'
24.
 
25.
echo $content."<hr>"
26.
 
27.
// NACH DEM ERSTELLEN DER ARRAYS ZEITMESSUNG STARTEN 
28.
$time_start = getmicrotime(); // Zeitmessung 
29.
 
30.
// OUTPUT GLOSSAR-PARSER  
31.
echo parse_glossar($content); 
32.
 
33.
// END 
34.
$time = getmicrotime() - $time_start
35.
echo "<p>Time: ".round ($time,5)." sec.</p>"
36.
 
37.
// --------- 
38.
// FUNCTIONS 
39.
// --------- 
40.
 
41.
function parse_glossar ($content) { 
42.
	// SPLIT INTO ARRAY 
43.
	$search = "/(<.*?<\/.*?>|<.*?\/>)/"
44.
	$parse_arr = preg_split($search, $content,-1,PREG_SPLIT_DELIM_CAPTURE); 
45.
	$parse_arr = array_map("parse_glossar_array", $parse_arr); 
46.
	return(join($parse_arr)); 
47.
48.
 
49.
function parse_glossar_array($parse_arr) { 
50.
	global $glossar_search_arr, $glossar_replace_arr;  
51.
	// strpos ist schneller als jedes preg etc. 
52.
	if (strpos($parse_arr,"<") === false) { 
53.
		// wenn kein HTML-Tags drin sind dann preg_replace  
54.
		return (preg_replace($glossar_search_arr, $glossar_replace_arr, $parse_arr,1)); 
55.
	} else
56.
		return ($parse_arr); 
57.
58.
59.
 
60.
// NUR FUER DIE ZEITMESSUNG 
61.
function getmicrotime(){ // GIBT IN MILLISECUNDEN ZURUECK 
62.
    list($usec, $sec) = explode(" ",microtime()); 
63.
    return ((float)$usec + (float)$sec); 
64.
65.
?>
Im Prinzip erst ein "preg_split" damit $content nach "<.*>" Tags gesplittet wird.
Dann ein "array_map" um jedes Element im Array schnell durch eine Funktion laufen zu lassen.
Die Funktion "parse_glossar_array" schaut dann nach ob im Element ein "<" vorkommt (mit strpos, dass ist sehr schnell). Wenn nicht wird das Array mit den Glossar-Begriffen mit "preg_replace" gefunden ersetzt. Danach wird alles wieder mit "join" zusammengesetzt.

Einzig das Glossar-Array wie oben beschrieben muss anders aufgebaut werden (ein Such- und ein Replace-Array).
Nach meinen Messungen ist das sehr schnell.

Gruß
Frank
Bitte warten ..
Mitglied: Guenni
LÖSUNG 17.06.2008, aktualisiert 05.12.2013
@scholl

Hi,

ich habe hier einen Codeschnipsel zu preg_replace_callback, der aus einer
Adresse in einem Text einen Link erstellt.

Analog dazu müsste es ja dann auch möglich sein, aus einem Link wieder eine Adresse zu machen, in dem man die entsprechenden Tags wieder entfernt.

01.
<? 
02.
$content = "Hier werden sie geholfen http://www.administrator.de, auf jeden Fall"
03.
 
04.
// Die Callback-Funktion 
05.
 
06.
function repl($erg){ 
07.
 return $erg[1].'<a href="'.($erg[2]=='www.'?'http://'.$erg[2]:$erg[2]).$erg[3].'"  
08.
target="_blank">'.$erg[2].$erg[3].'</a>'
09.
10.
 
11.
function mreplace($string){ 
12.
	$pattern = '#(^|\s)(https*://|ftp://|mailto:|news:|www\.)([^\s<>]+)#sm'
13.
  return preg_replace_callback($pattern,'repl',$string); 
14.
15.
 
16.
echo $content."<hr>"
17.
echo mreplace($content); 
18.
 
19.
?>
Den Original-Schnipsel von Slava findest du hier http://www.bituniverse.com/forum/s/viewtopic.php/t,216/postdays,0/posto ...

Gruß
Günni
Bitte warten ..
Neuester Wissensbeitrag
Windows 10

Powershell 5 BSOD

(8)

Tipp von agowa338 zum Thema Windows 10 ...

Ähnliche Inhalte
Heiß diskutierte Inhalte
Microsoft
Ordner mit LW-Buchstaben versehen und benennen (21)

Frage von Xaero1982 zum Thema Microsoft ...

Netzwerkmanagement
gelöst Anregungen, kleiner Betrieb, IT-Umgebung (18)

Frage von Unwichtig zum Thema Netzwerkmanagement ...

Windows Update
Treiberinstallation durch Windows Update läßt sich nicht verhindern (17)

Frage von liquidbase zum Thema Windows Update ...