regex Kommentare finden
bearbeitet von
Hallo Henry,
wenn Du es mit Regex machst, ja, dann musst du gruppieren. Deine Regex enthält bereits eine.
Ich würde allerdings so matchen: `/<!-+-\s*(.*?)\s*-+->/mg`
Zum einen überspringt sie den Whitespace zwischen Kommentarbegrenzer und Text, zum anderen ist deine Zeichengruppe [\s\S] etwas merkwürdig. \s ist Whitespace, und \S ist non-Whitespace. Also: alle Zeichen. Kurz: Ein Punkt.
Um auf Gruppeninhalte zuzugreifen, darfst Du aber 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.
~~~js
const commentPattern = /<!-+-\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:
~~~html
<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.
~~~js
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\-]*$/m;
for (let commentNode of getCommentNodes(document)) {
let commentText = commentNode.textContent.match(textOnly);
console.log(commentText);
}
~~~
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#iterables) 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.
_Rolf_
--
sumpsi - posui - obstruxi
regex Kommentare finden
bearbeitet von
Hallo Henry,
wenn Du es mit Regex machst, ja, dann musst du gruppieren. Deine Regex enthält bereits eine.
Ich würde allerdings so matchen: `/<!-+-\s*(.*?)\s*-+->/mg`
Zum einen überspringt sie den Whitespace zwischen Kommentarbegrenzer und Text, zum anderen ist deine Zeichengruppe [\s\S] etwas merkwürdig. \s ist Whitespace, und \S ist non-Whitespace. Also: alle Zeichen. Kurz: Ein Punkt.
Um auf Gruppeninhalte zuzugreifen, darfst Du aber 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.
~~~js
const commentPattern = /<!-+-\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...
outerHTML 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.
~~~js
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\-]*$/m;
for (let commentNode of getCommentNodes(document)) {
let commentText = commentNode.textContent.match(textOnly);
console.log(commentText);
}
~~~
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#iterables) 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.
_Rolf_
--
sumpsi - posui - obstruxi
regex Kommentare finden
bearbeitet von
Hallo Henry,
wenn Du es mit Regex machst, ja, dann musst du gruppieren. Deine Regex enthält bereits eine.
Ich würde allerdings so matchen: `/<!-+-\s*(.*?)\s*-+->/mg`
Zum einen überspringt sie den Whitespace zwischen Kommentarbegrenzer und Text, zum anderen ist deine Zeichengruppe [\s\S] etwas merkwürdig. \s ist Whitespace, und \S ist non-Whitespace. Also: alle Zeichen. Kurz: Ein Punkt.
Um auf Gruppeninhalte zuzugreifen, darfst Du aber 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.
~~~js
const commentPattern = /<!-+-\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...
outerHTML 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.
~~~js
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\-]$/m;
for (let commentNode of getCommentNodes(document)) {
let commentText = commentNode.textContent.match(textOnly);
console.log(commentText);
}
~~~
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#iterables) 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.
_Rolf_
--
sumpsi - posui - obstruxi
regex Kommentare finden
bearbeitet von
Hallo Henry,
wenn Du es mit Regex machst, ja, dann musst du gruppieren. Deine Regex enthält bereits eine.
Ich würde allerdings so matchen: `/<!-+-\s*(.*?)\s*-+->/mg`
Zum einen überspringt sie den Whitespace zwischen Kommentarbegrenzer und Text, zum anderen ist deine Zeichengruppe [\s\S] etwas merkwürdig. \s ist Whitespace, und \S ist non-Whitespace. Also: alle Zeichen. Kurz: Ein Punkt.
Um auf Gruppeninhalte zuzugreifen, darfst Du aber 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.
~~~js
const commentPattern = /<!-+-\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...
outerHTML 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. 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.
~~~js
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\-]$/m;
for (let commentNode of getCommentNodes(document)) {
let commentText = commentNode.textContent.match(textOnly);
console.log(commentText);
}
~~~
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#iterables) 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.
_Rolf_
--
sumpsi - posui - obstruxi
regex Kommentare finden
bearbeitet von
Hallo Henry,
wenn Du es mit Regex machst, ja, dann musst du gruppieren. Deine Regex enthält bereits eine.
Ich würde allerdings so matchen: `/<!-+-\s*(.*?)\s*-+->/mg`
Zum einen überspringt sie den Whitespace zwischen Kommentarbegrenzer und Text, zum anderen ist deine Zeichengruppe [\s\S] etwas merkwürdig. \s ist Whitespace, und \S ist non-Whitespace. Also: alle Zeichen. Kurz: Ein Punkt.
Um auf Gruppeninhalte zuzugreifen, darfst Du aber nicht match verwenden, es muss matchAll sein. Diese Funktion liefert einen Iterator, den Du mit for..of durchlaufen kannst.
~~~js
const commentPattern = /<!-+-\s*(.*?)\s*-+->/mg;
const htmlDocument = document.documentElement.outerHTML;
for (let match of htmlDocument.matchAll(commentPattern)) {
const commentText = match[1];
console.log(commentText);
}
~~~
Ich hätte aber mal wieder ein a-bärchen, das vor sich hin brummt. outerHTML 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. 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.
~~~js
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\-]$/m;
for (let commentNode of getCommentNodes(document)) {
let commentText = commentNode.textContent.match(textOnly);
console.log(commentText);
}
~~~
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#iterables) 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.
_Rolf_
--
sumpsi - posui - obstruxi