regex Kommentare finden
Henry
- html
- regex
Hallo,
function innerCOMMENT()
{
var pat = /<!-+-([\s\S]*?)-+->/mg;
var str = document.documentElement.outerHTML;
var ar_com = str.match(pat);
alert(ar_com);
}
Damit finde ich HTML-Kommentare innerhalb einer Seite. Dummerweise aber auch mit den Schlüsseln, also <!-- --> Natürlich lässt sich das ja wieder ersetzen/löschen, doch geht das nicht mit der regex selbst, dass die erst gar nicht die keys mit ausgibt?
Gruss
Henry
Hallo,
Damit finde ich HTML-Kommentare innerhalb einer Seite. Dummerweise aber auch mit den Schlüsseln, also <!-- --> Natürlich lässt sich das ja wieder ersetzen/löschen, doch geht das nicht mit der regex selbst, dass die erst gar nicht die keys mit ausgibt?
Hilft Gruppierung?
Gruß
Kalk
Hallo Tabellenkalk,
Hilft Gruppierung?
Wahrscheinlich schon, nur kapiere ich nicht wo ich das ansetzen soll.
https://regex101.com/r/AONkbc/1
Aber immer schon mein Problem mit Regex, tagelang endlose Experimente und ich blicke wieder einigermaßen durch, aber nach ein paar Monaten fang ich wieder bei Null an, weil alles wieder vergessen.
Aber auch im Netz nicht wirklich was brauchbares zu finden, vor allem überhapt zum Thema Kommentare filtern usw. Da gibts zwar einige endloslange pattern, aber ob das so sein muss…
Gruss
Henry
(Dieser Beitrag wurde editiert, um die groben Klöpse zu korrigieren, die ich mir geleistet habe - Rolf)
Hallo Henry,
wenn Du es mit Regex machst, ja, dann musst du gruppieren. Deine Regex enthält bereits eine.
Ich würde allerdings noch \s* hinzufügen:
/<!-+-\s*([\s\S]*?)\s*-+->/mg
um den Whitespace zwischen Kommentarbegrenzer und Text zu überspringen.
Die Zeichenklasse [\s\S] hatte mich zuerst verwundert, aber: Das ist völlig richtig. Ein Punkt wäre falsch, denn der matcht keine Zeilenumbrüche!
Wenn Du aber alle Treffer auf einmal finden und dann auf Gruppeninhalte zugreifen willst, darfst Du nicht match verwenden, es muss matchAll sein. Diese Funktion liefert einen Iterator, den Du mit for..of durchlaufen kannst. Jeder einzelne Match ist ein Array. Dieses Array enthält am Index 0 den kompletten Match für die Regex (also den ganzen Kommentar inclusive der Begrenzer), und dann für jede Gruppe einen weiteren Eintrag. Die Zuordnung Gruppe zu Arrayposition kannst Du Dir so merken: zur n-ten linken Klammer im Pattern gehört der Eintrag bei Index n. Für die erste Klammer brauchen wir also den Index 1.
const commentPattern = /<!-+-\s*([\s\S]*?)\s*-+->/mg;
const htmlDocument = document.documentElement.outerHTML;
for (let match of htmlDocument.matchAll(commentPattern)) {
const commentText = match[1];
console.log(commentText);
}
Das kann man so machen, aber...
Zum einen gibt es eine kleine Unschärfe. Stell Dir vor, jemand würde das hier schreiben:
<img alt="<!-- foo -->" src="...">
Das würdest Du als Kommentar finden. Es ist aber keiner. Ja okay, das macht eigentlich auch niemand.
Zum anderen ist outerHTML an sich nicht so toll. Es muss über das komplette DOM rennen und einen String generieren. Und den jagst Du dann durch eine g-Regex. Das ist, gerade bei längerem HTML, ziemlich aufwändig.
Eleganter kann es sein, einen rekursiven Generator über das DOM zu schicken und nach Kommentar-Nodes zu suchen. Wenn Du danach auf die textContent-Eigenschaft der gefundenen Kommentare zugreifst, hast Du das Problem von <!-- --> nicht mehr. Dafür ein anderes, dazu gleich mehr.
function* getCommentNodes(node) {
for (let childNode of node.childNodes) {
if (childNode.nodeType == Node.COMMENT_NODE)
yield childNode;
else
yield* getCommentNodes(childNode);
}
}
let textOnly = /^[\s\-]*([\s\S]*?)[\s\-]*$/;
for (let commentNode of getCommentNodes(document)) {
let commentText = commentNode.textContent.match(textOnly);
console.log(commentText[1]);
}
Ein Generator ist eine Funktion, die einen Iterator zurückgibt. Das Bereitstellen der einzelnen Werte erfolgt mit yield. Eine schicke Eigenschaft von JavaScript-Generatoren ist, dass ein Generator seinen Job auch an Subgeneratoren delegieren kann, mit yield*. Letztlich ist function* eine dicke Kruste aus Syntaxzucker für ein komplexes Gebilde, das unter der Haube läuft, aber aus Programmierersicht ist diese Form der Programmierung sehr elegant. Es sieht nämlich so aus, als würde man eine Pipeline programmieren. getCommentNodes und die auslesende for..of Schleife scheinen unabhängig voneinander zu laufen, und die for..of Schleife bekommt vom Generator Stück für Stück die Werte angereicht. Wenn Du wissen willst, wie widerlich der Fraß unter der Syntaxzuckerkruste ist, dann schau Dir hier die user-defined iterables an...
Man muss über die childNodes Collection laufen, weil die Kommentare keine HTML Elemente sind und darum in der children Collection nicht enthalten sind.
Restproblem: Ein Kommentar <!----- Hallo ------>
würde als
--- Hallo ----
gefunden werden. Und JavaScript hat keine Trim-Funktion, die andere Zeichen als Whitespace trimmen kann. Man muss dafür am Ende also doch wieder eine Regex verwenden, um die zu ignorieren. Dafür habe ich die textOnly
Regex gemacht. Aber diese läuft nur über einen einzelnen Kommentar, nicht über das ganze HTML Dokument. Beachte, dass diese Regex keine m Option tragen darf, weil ^ und $ dann Zeilenumbrüche matchen würden. Das wollen wir bei mehrzeiligen Kommentaren gerade nicht.
Rolf
Hallo Rolf,
danke für die ausführliche Antwort. matchAll kannte ich noch nicht und habe es offensichtlich auch noch nicht ganz verstanden, weil bisher alle Versuche fehl schlugen. Leider auch deine andere Funktion.
Ich habe es jetzt nochmal so aufgebaut, wie du hier beschreibst. Was mache ich falsch?
Gruss
Henry
Hallo Henry,
du machst von Dir aus nichts falsch. Aber ich habe dreifachen Unsinn geredet. Ich bitte um Entschuldigung 😟. Immerhin konnte ich daraus etwas lernen.
(1) Du hattest [\s\S]
verwendet. Ich sagte: das ist das gleiche wie .
Aber [\s\S] war richtig. TIL[1]: Der Punkt matcht „alles, außer Zeilenendezeichen“. Nur [\s\S] matcht wirklich alles.
(2) m Option für die textOnly Regex
Das war nun ein richtiger Hirnfurz von mir. "m" als Option bedeutet, dass ^ und $ Zeilenendezeichen matchen. Man verwendet m, wenn man Zeilengrenzen in einem String per Regex beachten will. Aber gerade das wollen wir nicht. Das m muss weg.
let textOnly = /^[\s\-]*([\s\S]*?)[\s\-]*$/;
(3) Ich schwalle über Gruppen herum und verwende sie dann nicht.
matchAll liefert eine Iteration von Matches. Ein Match ist ein Array. Und wir wollen die erste Gruppe aus der Regex haben. Das wäre an Index 1 des Arrays zu finden. Statt auf commentText musst Du also auf commentText[1] zugreifen.
Guckst Du hier
Ich werde mein Posting von gestern editieren.
Rolf
Today I Learned ↩︎
Hallo Rolf,
danke dir. Perfekt.
Gruss
Henry
Hallo Henry,
das Ergebnis dieses Threads findet sich jetzt auch im Wiki.
Rolf
Hallo Rolf,
kleiner Nachtrag.
let textOnly = /^[\s\-]*([\s\S]*?)[\s\-]*$/;
Guckst Du hier
Das Pattern scheint noch nicht ganz richtig, weil es comment 2 nicht findet. Ich habs auch mal mit der anderen Pattern versucht, da kommt dann überraschenderweise gar nichts. Deine andere Variante funktioniert aber tadelos.
Gruss
Henry
HTML und RegEx wird immer irgendwann schiefgehen. Besser wäre es, völlig darauf zu verzichten.
Ich habe mal gesucht und folgenden Thread gefunden:
How do I get an HTML comment with javascript.
Die akzeptiere Antwort scheint eine passende Lösung zu sein.
Hallo kai345,
HTML und RegEx wird immer irgendwann schiefgehen
ein wenig zu pauschal.
Besser wäre es, völlig darauf zu verzichten.
wenns geht, sicherlich.
Ich habe mal gesucht und folgenden Thread gefunden:
How do I get an HTML comment with javascript.
Habe ich mir angeschaut und mit experimentiert. Ebenso überhaupt alles gesucht was ich finden konnte zu SHOW_COMMENT und node.filter
Die akzeptiere Antwort scheint eine passende Lösung zu sein.
Nein, es werden nicht alle Kommentare gefunden und glaube auch wenn wären es nur die HTML Kommentare <!--. JS und CSS bleiben aussen vor. Natürlich habe ich unzählige Alternativen auf Basis von SHOW_COMMENT probiert, doch alles sehr viel unzuverlässiger als die Regex.
Gruss
Henry
Hallo,
Die akzeptiere Antwort scheint eine passende Lösung zu sein.
Nein, es werden nicht alle Kommentare gefunden und glaube auch wenn wären es nur die HTML Kommentare <!--. JS und CSS bleiben aussen vor.
das ist logisch, denn erstens sind die keine HTML- oder DOM-Nodes, sondern aus der Sicht des DOM beliebige Textfitzel in einem style- oder script-Element; zweitens gilt für Kommentare in JS oder CSS eine ganz andere Syntax, daher wirst du sie auch mit einem RegEx nicht finden, der auf das Muster von HTML-Kommentaren abgestimmt ist.
Natürlich habe ich unzählige Alternativen auf Basis von SHOW_COMMENT probiert, doch alles sehr viel unzuverlässiger als die Regex.
Die Frage ist: Was willst du eigentlich erreichen?
Live long and pros healthy,
Martin
Hallo Der,
das ist logisch, denn erstens sind die keine HTML- oder DOM-Nodes, sondern aus der Sicht des DOM beliebige Textfitzel in einem style- oder script-Element; zweitens gilt für Kommentare in JS oder CSS eine ganz andere Syntax,
genau
daher wirst du sie auch mit einem RegEx nicht finden, der auf das Muster von HTML-Kommentaren abgestimmt ist.
mit einem vielleicht ein wenig zu komplex, aber ich denke das habe ich schon anders gelöst:
function commentFinder(p='html'){
var responseData = document.documentElement.outerHTML;
if(p == 'html'){var regex = /<!-+-\s*([\s\S]*?)-+->/g; }
else if(p == 'css'){var regex = /\/\*\s([\s\S]*?)\*\//g;}
else if(p == 'js'){var regex = /\/\/#\s(.*)/g;}
else if(p == 'js2'){var regex = /\/\/.*#.\s*(\S.*)/g;} // geht auch wenn # unregelmässig
//#\s(.*)
var arx = new Array();
while(match_ar = regex.exec(responseData))
{
//console.log(match[1]);
txout.value += match_ar[1] + "\r\n";
arx.push(match_ar[1]);
}
// alert(arx.length);
// alert(arx);
return arx;
} // ###end of func.
Die Frage ist: Was willst du eigentlich erreichen?
Kommentare finden und den Inhalt nach Belieben weiter verarbeiten.
Gruss
Henry
Hallo Henry,
Die Frage ist: Was willst du eigentlich erreichen?
Kommentare finden
Das ist offensichtlich.
und den Inhalt nach Belieben weiter verarbeiten.
Also handelt es sich nicht um deine eigenen Inhalte.
Bis demnächst
Matthias
Hallo Matthias,
Kommentare finden
Das ist offensichtlich.
anscheinend nicht 😉
und den Inhalt nach Belieben weiter verarbeiten.
Also handelt es sich nicht um deine eigenen Inhalte.
doch!
Der Grund ist schlichtweg, bei mir sammeln sich hunderte Scripte die ich auch mehr oder weniger kommentiert habe. Nun möchte ich, weil ich viele Kommentare selbst nicht mehr verstehe, das mal auf den neusten Stand bringe und gleichzeitig ein Dokusystem schaffen, dass mir allgemein die Arbeit mit sowas erleichtert.
Gruss
Henry
n'Abend,
Der Grund ist schlichtweg, bei mir sammeln sich hunderte Scripte die ich auch mehr oder weniger kommentiert habe. Nun möchte ich, weil ich viele Kommentare selbst nicht mehr verstehe, das mal auf den neusten Stand bringe und gleichzeitig ein Dokusystem schaffen, dass mir allgemein die Arbeit mit sowas erleichtert.
das heißt, du hast das Thema Kommentare zum Code bisher eher vernachlässigt, mehr oder weniger aus Pflichtgefühl irgendwas hingeschrieben, was aber nicht wirklich aussagekräftig ist - und jetzt hast du den guten Vorsatz gefasst, das in Zukunft und auch für die Vergangenheit besser zu machen.
Wenn ich in meinen Programmcodes (C, x86-Assembler, Javascript, PHP) der letzten 20 Jahre die Kommentare isolieren würde, ergäbe sich in den meisten Fällen ein Textdokument, das die Funktion des Programms mehr oder weniger gut nachvollziehbar beschreibt.
Das ist auch seit vielen Jahren mein Anspruch. So wird eine zusätzliche technische Dokumentation fast überflüssig.
Live long and pros healthy,
Martin
Hallo Der,
Wenn ich in meinen Programmcodes (C, x86-Assembler, Javascript, PHP) der letzten 20 Jahre die Kommentare isolieren würde, ergäbe sich in den meisten Fällen ein Textdokument, das die Funktion des Programms mehr oder weniger gut nachvollziehbar beschreibt.
Das ist auch seit vielen Jahren mein Anspruch. So wird eine zusätzliche technische Dokumentation fast überflüssig.
das ist genau mein Grundgedanke, weiss aber auch nicht ob ich den in Zukunft erreichen kann und wie du das so akribisch hinbekommst. Denn ist nun mal so, ich experimentiere gerne, und da sammeln sich dann zu einm Thema schnell mal >20 Variationen an. Die speichere ich mit den notwendigsten Infos um schnell weiter arbeiten zu können. Jedes Einzelexperiment erfolgreich zu dokumentieren ist schon aufwendiger, na ja vielleicht klappts besser mit dem Tool das ich gerade bastle.
Gruss
Henry
Hallo,
das ist genau mein Grundgedanke, weiss aber auch nicht ob ich den in Zukunft erreichen kann und wie du das so akribisch hinbekommst.
ich glaube, ein wichtiger Faktor ist, dass ich selten spontan drauflos code. Meistens sind Flowcharts, Skizzen der Datenmodelle und -relationen wichtige Vorstufen, in der Regel traditionell auf Papier. Und in der Phase wird auch viel wieder verworfen und nochmal neu angesetzt.
Oft entsteht auch eine Art Bedienungsanleitung (zumindest für das Ergebnis, das ich gern hätte), bevor ich das erste Stück Code schreibe. Das entspricht dann in etwa dem Pflichtenheft.
Denn ist nun mal so, ich experimentiere gerne, und da sammeln sich dann zu einm Thema schnell mal >20 Variationen an.
Das tu ich auch hin und wieder, aber dann isoliert vom eigentlichen Projekt. Erst wenn ich beim Experimentieren einen Teilerfolg erziele und dieses eine Microproblem zufriedenstellend gelöst habe, geht das wieder in den produktiven Code ein. Mit entsprechender Kommentierung.
Live long and pros healthy,
Martin
Hallo Henry,
Der Grund ist schlichtweg, bei mir sammeln sich hunderte Scripte die ich auch mehr oder weniger kommentiert habe. Nun möchte ich, weil ich viele Kommentare selbst nicht mehr verstehe, das mal auf den neusten Stand bringe und gleichzeitig ein Dokusystem schaffen, dass mir allgemein die Arbeit mit sowas erleichtert.
Ah. ok. Das ist nachvollziehbar. Solltest du dann nicht besser die Möglichkeiten der IDE / des Editors nutzen, anstatt mit JavaScript auf die Seite loszulaufen?
Und meinst du denn, dass die hintereinandergereihten HTML-Kommentare ohne den dazugehörenden Quelltext brauchbar sind?
weil ich viele Kommentare selbst nicht mehr verstehe,
Wenn sie dann so ganz alleine stehen, wird es nicht besser sein, weil du ja überhaupt keinen Anknüpfungspunkt zum Code mehr hast. Das heißt, du kappst auch noch die letzte Möglichkeit, den Kommentar zu verstehen.
das mal auf den neusten Stand bringe
das kann ja dann nur heißen, die Kommentare zu ergänzen.
und gleichzeitig ein Dokusystem schaffen
Schau dir mal die Konventionen bei JavaDoc an. Wenn man für sich selbst solche oder ähnliche Regeln festlegt, macht man es sich bestimmt einfacher. Und weil du dann den festgelegten Regeln folgst, machst du es dem Parser dann auch einfacher.
Bis demnächst
Matthias
Hallo Henry,
wieder mal was gelernt, createNodeIterator kannte ich überhaupt nicht. Meine getCommentNodes-Funktion sollte aber genau das gleiche liefern wie createNodeIterator mit der SHOW_COMMENTS Option.
Nein, es werden nicht alle Kommentare gefunden und glaube auch wenn wären es nur die HTML Kommentare <!--
Duh, natürlich nur die HTML Kommentare. Nur die stehen im DOM. Was ich übersehen habe, sind Kommentare in Templates. Die sind über createNodeIterator und auch über meine Lösung nicht zu finden, weil der Inhalt eines templates über die content-Eigenschaft zu finden ist und nicht über die childNode Collection.
JS und CSS bleiben aussen vor.
Das ist ja nun keine Kritik, sondern ein rhetorisches Foul. Von JS und CSS Kommentaren war bisher keine Rede, und deine Regex findet die genauso wenig.
Natürlich habe ich unzählige Alternativen auf Basis von SHOW_COMMENT probiert, doch alles sehr viel unzuverlässiger als die Regex.
Könntest Du die Stärken deiner Regex im Vergleich zu createNodeIterator vielleicht erläutern? Möchtest Du uns deine zuverlässige Regex nochmal zeigen? Ich bin sicher, dass ich nicht lange brauchen werde, um Spezialfälle zu konstruieren, an denen deine Regex sich die Zähne ausbeißt und die über einen NodeIterator problemlos gefunden werden.
Deine Regex hat allerdings einen Vorteil: Man muss dafür kein DOM aufbauen. Man kann beliebige HTML Quellen als String einlesen und damit verarbeiten. Ein NodeIterator braucht ein DOM. D.h. ein JS, das ein fremdes HTML Dokument auf Kommentare zerlegt, ist auf die von mir gezeigte Art nicht machbar. Ist das ein Kriterium?
Rolf
Hallo Rolf,
JS und CSS bleiben aussen vor.
Das ist ja nun keine Kritik, sondern ein rhetorisches Foul. Von JS und CSS Kommentaren war bisher keine Rede, und deine Regex findet die genauso wenig.
Genau, könnte man wahrscheinlich alles in einem Pattern reinpacken, habe mich aber für vierscheidenen Funktionsparameter entschieden.
Natürlich habe ich unzählige Alternativen auf Basis von SHOW_COMMENT probiert, doch alles sehr viel unzuverlässiger als die Regex.
Könntest Du die Stärken deiner Regex im Vergleich zu createNodeIterator vielleicht erläutern?
Kann ich nicht, ist nur im Moment leichter verständlich für mich.
Möchtest Du uns deine zuverlässige Regex nochmal zeigen?
Zuverlässig ist relativ, zumindest bisherige Tests laufen zufriedenstellend. Einzig, die letzte Pattern ist noch unausgegoren aber auch nicht weiter schlimm, weil ich sie normalerweise nicht brauche.
Ich bin sicher, dass ich nicht lange brauchen werde, um Spezialfälle zu konstruieren, an denen deine Regex sich die Zähne ausbeißt und die über einen NodeIterator problemlos gefunden werden.
Kann möglich sein, wüsste aber kein Beispiel.
Gruss
Henry
Hallo Henry,
Kann ich nicht, ist nur im Moment leichter verständlich für mich.
Gut. Wenn das dein Hauptgrund ist, dann steh auch dazu und erkläre andere Lösungen nicht als technisch unzureichend.
Wenn ich Schwächen deiner Regexe suche... hm. Kontextwechsel ist das wesentliche Problem. Ohne was verändert zu haben:
Okay, das ist Klugscheißerei. Du suchst nach /* */ Kommentaren, egal wo. Aber Du weißt nicht, ob Du einen CSS oder JS Kommentar gefunden hast. Ist das unwichtig für Dich?
//
Kommentaren die ein # enthalten, und dann auch nur den Text hinter dem #
? Ein einzeiliger Javascript-Kommentar benötigt kein #Mit ein paar kleinen, boshaften Änderungen:
document.write("<!-- das ist ein Test -->");
In folgenden HTML Fragment werden zwei HTML Kommentare gefunden. Da ist aber nur einer.
<img src="#" alt="<!--">
Das ist ein Test!
<!-- Ende der Testsektion -->
Das ist das, was ich mit Kontextproblemen meinte.
In folgendem HTML Fragment wird ein Singleline Kommentar gefunden. Da ist aber keiner. Ebenfalls ein Kontextproblem.
<!-- // #### Wichtig ##### //
-- Dieser Kommentar darf nicht entfernt werden
-->
Hinzu kommt ein Regex-Fehler. Ausgegeben wird der Kommentar als # //
. Die erwartete Ausgabe wäre wohl #### Wichtig ####
. Grund: Das Matching von .* zu Beginn ist greedy. Es muss aber non-greedy sein (also .?). Statt .?. könntest Du auch .+? verwenden.
Ich wollte Dich auch noch mit der CSS Eigenschaft grid-area ärgern, weil deren Syntax bis zu drei Schrägstriche enthalten darf. Aber dazwischen muss immer etwas kommen, die Zeichenfolge "//" darin ist nicht syntaktisch zulässig. Das ist es im CSS wohl nirgends (außer in einem String). Glück gehabt 😜
Dann habe ich einen Test mit bösem JavaScript gemacht.
if (a <!--q) { ... }
Aber weil Browser aus historischen Gründen den Rest der Zeile hinter <!-- ignorieren, ist das kein Code, der in der freien Wildbahn vorkommen kann. Glück gehabt 😉
Rolf
Hallo Rolf,
Gut. Wenn das dein Hauptgrund ist, dann steh auch dazu und erkläre andere Lösungen nicht als technisch unzureichend.
habe ich nicht, zumindest nicht gewollt. Habe nur objektiv gesagt was noch nicht geht, gleichzeitig deine Lösung auch als "akzeptierte Antwort" deklariert, oder?
Darüber hinaus, habe ich nun mehrere Optionen Kommentare zu finden, deine eingeschlossen. Welche davon im Nachhinein für mich am praktikabelsten ist, weiss ich jetzt noch nicht abzuschätzen.
- Wieso suchst Du nur nach
//
Kommentaren die ein # enthalten, und dann auch nur den Text hinter dem#
? Ein einzeiliger Javascript-Kommentar benötigt kein #
Nein, aber ich muss mich für einen eigenen Stil festlegen und bei mir ist das eben meist so. Auf die Art habe ich verschiedene Arten von einzeiligen Kommentaren, so dass ich die Funktion weiter verfeinern kann und verliere gleichzeitig nicht den Bezug zu PHP.
Gruss
Henry