Javascript Heredoc


109

Ich brauche so etwas wie Heredoc in JavaScript. Hast du irgendwelche Ideen dafür? Ich benötige browserübergreifende Funktionen.

Ich habe das gefunden:

heredoc = '\
<div>\
    <ul>\
        <li><a href="#zzz">zzz</a></li>\
    </ul>\
</div>';

Ich denke, es wird für mich funktionieren. :) :)


6
Duplikat von stackoverflow.com/questions/805107/… mit detaillierteren Antworten.
Chadwick

4
Wenn ich "\" hinzufügen muss, runzele ich jedes Mal die Stirn. Imho, keine normale Syntax für mehrzeilige Zeichenfolgen zu haben, ist völlig ungerechtfertigt. Und sie hätten es in jeder Version hinzufügen können, aber sie taten es nicht.
Lex


Heutzutage geschieht dies mit Vorlagenliteralen, wie im möglichen Duplikat gezeigt (hier gibt es keine aktualisierte Antwort).
Brasofilo

Antworten:


77

Versuchen Sie ES6 String Template , Sie können so etwas tun

var hereDoc = `
This
is
a
Multiple
Line
String
`.trim()


hereDoc == 'This\nis\na\nMultiple\nLine\nString'

=> true

Sie können diese großartige Funktion heute mit 6to5 oder TypeScript nutzen


2
Dies gilt, wenn Sie nur mehrzeilige Zeichenfolgen möchten. Da Sie das Symbol, das Ihre Zeichenfolge umschließt, nicht wirklich ändern können, ist es nicht wirklich heredoc.
Peeyush Kushwaha

3
Nur als Hinweis: Die ursprüngliche Frage wurde vor 5 Jahren gestellt, bevor ES6 verfügbar war. Dies ist die beste Vorgehensweise für die Zukunft, da auch die Leistung besser ist.
Henry Tseng

2
@HenryTseng, schlagen Sie also vor, dass die Antworten auf diese Frage auf alte Technologien zugeschnitten sein sollten, die vor 5 Jahren existierten? Wenn die Frage noch offen ist, sollten neue Technologien genutzt werden, wie sie im Laufe der Zeit entstanden sind. Auf diese Weise können neue Benutzer mit demselben Problem hier "nicht archäologische" Informationen finden.
Asiby

1
Nein, ich habe einen Kommentar dazu abgegeben, warum diese Lösung früher nicht wichtiger war. Es scheint definitiv der unterstützte Weg zu sein, wenn es keine Kompatibilitätsprobleme gibt.
Henry Tseng


37

Wie wäre es damit:

function MyHereDoc(){
/*HERE
<div>
   <p>
      This is written in the HEREDOC, notice the multilines :D.
   </p>
   <p>
      HERE
   </p>
   <p>
      And Here
   </p>
</div>
HERE*/
    var here = "HERE";
    var reobj = new RegExp("/\\*"+here+"\\n[\\s\\S]*?\\n"+here+"\\*/", "m");
    str = reobj.exec(MyHereDoc).toString();
    str = str.replace(new RegExp("/\\*"+here+"\\n",'m'),'').toString();
    return str.replace(new RegExp("\\n"+here+"\\*/",'m'),'').toString();
}

//Usage 
document.write(MyHereDoc());

Ersetzen Sie einfach "/ * HIER" und "HIER * /" durch ein Wort Ihrer Wahl.


4
Geben alle Browser / Engines die Kommentare in Function.toString () zurück? das ist sehr klug
gcb

Funktioniert in der Chrome-Konsole
Omn

4
Funktioniert nicht, wenn Sie einen abschließenden Kommentar */in Ihrem Heredoc haben.
Narigo

2
Ich würde empfehlen, die Antwort von Nate Ferrero zu verwenden, da dies ein verfeinertes und optimiertes Beispiel ist. Meins verwendet 3 separate regEx-Aufrufe und ist eher ein Proof of Concept.
Zv_oDD

1
Sehr klug ... aber Sie können nicht garantieren, dass es in Zukunft funktionieren wird. Es ist zu implementierungsabhängig, um eine gute Praxis zu sein.
Pierre-Olivier Vares

33

Aufbauend auf der Antwort von Zv_oDD habe ich eine ähnliche Funktion zur einfacheren Wiederverwendung erstellt.

Warnung: Dies ist eine nicht standardmäßige Funktion vieler JS-Interpreter und wird wahrscheinlich irgendwann entfernt. Da ich jedoch ein Skript erstelle, das nur in Chrome verwendet werden soll, verwende ich es! Verlassen Sie sich bei Websites mit Kundenkontakt niemals darauf!

// Multiline Function String - Nate Ferrero - Public Domain
function heredoc(fn) {
  return fn.toString().match(/\/\*\s*([\s\S]*?)\s*\*\//m)[1];
};

Verwenden:

var txt = heredoc(function () {/*
A test of horrible
Multi-line strings!
*/});

Kehrt zurück:

"A test of horrible
Multi-line strings!"

Anmerkungen:

  1. Der Text wird an beiden Enden abgeschnitten, sodass zusätzliche Leerzeichen an beiden Enden in Ordnung sind.

Änderungen:

02.02.2014 - geändert, um den Funktionsprototyp überhaupt nicht zu beeinträchtigen und stattdessen den Namen heredoc zu verwenden.

26.05.2017 - Whitespace aktualisiert, um moderne Codierungsstandards widerzuspiegeln.


1
Ich würde hereDoc () als meinen Funktionsnamen verwenden, aber dieser Code funktionierte einwandfrei beim Laden meines 40-KB-Zeilen-Protokollspeicherauszugs in eine Variable in der Chrome-Konsole
Omn

Warum sollten Sie eine Instanz einer Funktion erstellen und auf die veraltete Eigenschaft __ proto __ zugreifen? Warum nicht einfach Function.prototype.str = function () {...}?
John Kurlak

@ JohnKurlak das ist noch besser! Ich glaube nicht, dass mir bewusst war, dass dies möglich war, als ich die Antwort schrieb.
Nate Ferrero

2
@NateFerrero - Super Antwort, danke! Eine eigene Erweiterung als separate Antwort hinzugefügt.
Andrew Cheong

Auf meinem Android-Gerät nexus 4 mit 5.0.1 funktioniert dies unter Chrome nicht mehr. Aus irgendeinem Grund werden Leerzeichen und Kommentare gelöscht. Ich kann nicht herausfinden, ob dies eine Einstellung ist, aber es ist definitiv auf der Client-Seite. Irgendwelche Ideen für eine Problemumgehung?
MLU

19

Je nachdem, welche JS / JS-Engine Sie verwenden (SpiderMonkey, AS3), können Sie einfach Inline-XML schreiben, in das Sie Text in mehrere Zeilen einfügen können, z. B. heredoc:

var xml = <xml>
    Here 
    is 
    some 
    multiline 
    text!
</xml>

console.log(xml.toXMLString())
console.log(xml.toString()) // just gets the content

13

ES6 Template Strings verfügt über eine Heredoc-Funktion.

Sie können Zeichenfolgen deklarieren, die von einem Back-Tick (``) eingeschlossen sind, und können durch mehrere Zeilen erweitert werden.

var str = `This is my template string...
and is working across lines`;

Sie können auch Ausdrücke in Vorlagenzeichenfolgen einfügen. Diese werden durch das Dollarzeichen und geschweifte Klammern ( ${expression}) angezeigt .

var js = "Java Script";
var des = `Template strings can now be used in ${js} with lot of additional features`;

console.log(des); //"Template strings can now be used in Java Script with lot of additional features"

Es gibt in der Tat mehr Funktionen wie Tagged Temple Strings und Raw Strings. Die Dokumentation finden Sie unter

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings


8

Es tut mir leid , eine separate Antwort für lediglich eine Erweiterung der Antwort von @ NateFerrero zu schreiben , aber ich halte es auch nicht für angebracht, seine Antwort zu bearbeiten. Bitte stimmen Sie @NateFerrero zu, wenn diese Antwort für Sie nützlich war.

tl; dr - Für diejenigen, die Blockkommentare in ihrem Heredoc verwenden möchten ...

Ich brauchte hauptsächlich Javascript-Heredocs, um einen CSS-Block zu speichern, z

var css = heredoc(function() {/*
    /**
     * Nuke rounded corners.
     */
    body div {
        border-top-left-radius: 0 !important;
        border-top-right-radius: 0 !important;
        border-bottom-right-radius: 0 !important;
        border-bottom-left-radius: 0 !important;
    }
*/});

Wie Sie jedoch sehen können, kommentiere ich gerne mein CSS, und leider (wie durch die Syntaxhervorhebung angedeutet) beendet der erste */den Gesamtkommentar und bricht den Heredoc.


Für diesen speziellen Zweck (CSS) bestand meine Problemumgehung darin, hinzuzufügen

.replace(/(\/\*[\s\S]*?\*) \//g, '$1/')

an die Kette in @ NateFerrero's heredoc; in vollständiger Form:

function heredoc (f) {
    return f.toString().match(/\/\*\s*([\s\S]*?)\s*\*\//m)[1].replace(/(\/\*[\s\S]*?\*) \//g, '$1/');
};

und verwenden Sie es, indem Sie ein Leerzeichen zwischen *und /für "innere" Blockkommentare einfügen, wie folgt:

var css = heredoc(function() {/*
    /**
     * Nuke rounded corners.
     * /
    body div {
        border-top-left-radius: 0 !important;
        border-top-right-radius: 0 !important;
        border-bottom-right-radius: 0 !important;
        border-bottom-left-radius: 0 !important;
    }
*/});

Der replacefindet /* ... * /und entfernt einfach den Raum, um zu machen /* ... */, wodurch der Heredoc erhalten bleibt, bis er aufgerufen wird.


Sie können die Kommentare natürlich ganz mit entfernen

.replace(/\/\*[\s\S]*?\* \//g, '')

Sie können //Kommentare auch unterstützen , wenn Sie sie der Kette hinzufügen:

.replace(/^\s*\/\/.*$/mg, '')

Sie können aber auch etwas anderes als den einzigen Raum zwischen tun *und /wie ein -:

    /**
     * Nuke rounded corners.
     *-/

Wenn Sie den regulären Ausdruck nur entsprechend aktualisieren:

.replace(/(\/\*[\s\S]*?\*)-\//g, '$1/')
                          ^

Oder möchten Sie eine beliebige Anzahl von Leerzeichen anstelle eines einzelnen Leerzeichens?

.replace(/(\/\*[\s\S]*?\*)\s+\//g, '$1/')
                          ^^^

2
Cool! Das war eine bekannte Einschränkung bei meiner Methode, ich mag es :)
Nate Ferrero

8

Sie können CoffeeScript verwenden , eine Sprache, die bis zu JavaScript kompiliert wird. Der Code kompiliert eins zu eins in das entsprechende JS, und zur Laufzeit gibt es keine Interpretation.

Und natürlich hat es Heredocs :)


24
Die richtige Antwort lautet nein. CoffeeScript und EJS könnten als Vorschläge verwendet werden.
Alvincrespo

4
CoffeeScript ist die richtige Antwort auf die meisten JS-Probleme, auf die ich gestoßen bin. Wenn Sie mehr als eine unbedeutende Menge an JS schreiben (und Ihre Zeit und Energie schätzen), sind Sie es sich selbst schuldig, es zu verwenden.
Brandon

5
Ich denke, dies ist eine gute Antwort, da es eine einfache Möglichkeit bietet, das Fehlen von Heredoc in Javascript zu umgehen. Hat mir viel Zeit gespart.
Stofke

3
Wenn Sie nur einen Teil von js möchten, sich aber nicht mit dem eigentlichen Schreiben befassen möchten: coffeescript.org und verwenden Sie die Schaltfläche "Try Coffeescript".
JCollum

1
Dies ist eher eine Antwort als die am höchsten bewertete, die im Grunde nur ... "nein" ist. Ich hasse solche Antworten.
Matt Fletcher

7

ES5 und frühere Versionen

(function(){/**
some random
multi line
text here
**/}).toString().slice(15,-5);

ES6 und spätere Versionen

`some random
multi line
text here`

Ergebnis

some random
multi line
text here

am besten einfach antworten
Benjamin

1
Das alte Ding ist ein unglaublich brutaler Hack: /
Shayne

1

Sie können Sweet.js-Makros verwenden, um es so hinzuzufügen, wie es von Tim Disney in diesem Beitrag erstellt wurde

Beachten Sie, dass bei diesem Ansatz stattdessen Backticks als Zeichenfolgenbegrenzer verwendet werden:

let str = macro {
    case {_ $template } => {
        var temp = #{$template}[0];
        var tempString = temp.token.value.raw;
        letstx $newTemp = [makeValue(tempString, #{here})];
        return #{$newTemp}
    }
}

str `foo bar baz`

1

Wie andere bereits gesagt haben, bieten ES6-Vorlagenzeichenfolgen das meiste, was herkömmliche Heredocs bieten.

Wenn Sie noch einen Schritt weiter gehen und eine mit Tags versehene Vorlagenzeichenfolge verwenden möchten, theredocist dies eine nette Dienstprogrammfunktion, mit der Sie Folgendes tun können:

if (yourCodeIsIndented) {
  console.log(theredoc`
    Theredoc will strip the
    same amount of indentation
    from each line.

      You can still indent
      further if you want.

    It will also chop off the
    whitespace-only first and
    last lines.
  `)
}

0

Wenn Sie HTML und jQuery zur Hand haben und die Zeichenfolge gültiges HTML ist, kann dies nützlich sein:

<div id="heredoc"><!--heredoc content
with multiple lines, even 'quotes' or "double quotes",
beware not to leave any tag open--></div>
<script>
var str = (function() {
   var div = jQuery('#heredoc');
   var str = div.html();
   str = str.replace(/^<\!--/, "").toString();
   str = str.replace(/-->$/, "").toString();
   return str;
})();
</script>

Wenn der Text dazwischen die Kommentare "<! - ->" enthält, funktioniert dies ebenfalls, aber ein Teil des Textes ist möglicherweise sichtbar. Hier ist die Geige: https://jsfiddle.net/hr6ar152/1/


0
// js heredoc - http://stackoverflow.com/a/32915549/466363
// a function with comment with eval-able string, use it just like regular string

function extractFuncCommentString(func,comments) {
  var matches = func.toString().match(/function\s*\(\)\s*\{\s*\/\*\!?\s*([\s\S]+?)\s*\*\/\s*\}/);
  if (!matches) return undefined;
  var str=matches[1];

   // i have made few flavors of comment removal add yours if you need something special, copy replacement lines from examples below, mix them
  if(comments===1 )
  {
   // keep comments, in order to keep comments  you need to convert /**/ to / * * / to be able to put them inside /**/ like /*    / * * /    */
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   )
  }
  else if(comments===2)
  {
   // keep comments and replace singleline comment to multiline comment
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
   )
  }
  else if(comments===3)
  {
   // remove comments
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
     )
  }
  else if(comments===4)
  {
   // remove comments and trim and replace new lines with escape codes
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
      .trim() // after removing comments trim and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else if(comments===5)
  {
   // keep comments comments and replace strings, might not suit when there are spaces or comments before and after quotes 
   // no comments allowed before quotes of the string
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */
      .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
      .trim() // trim space around quotes to not escape it and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else 
  return str
}

Beispiel

var week=true,b=123;
var q = eval(extractFuncCommentString(function(){/*!

// this is a comment     


'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc
'
*/},4));

mit Cache: - Erstellen Sie eine einfache Vorlagenfunktion und speichern Sie die Funktion: (das zweite Mal funktioniert schnell)

var myfunction_sql1;
function myfunction(week,a){


    if(!myfunction_sql1) eval('myfunction_sql1=function(week,a){return ('+extractFuncCommentString(function(){/*!
'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc

'*/},4)+')}');
    q=myfunction_sql1(week,a);
    console.log(q)
}
myfunction(true,1234)

1
Ganz unterschiedliche Ergebnisse in FF und Chrome.
Dave Newton

was ist unterschiedlich? Gerade in Chrome und FF getestet und ich bekomme genau die gleichen Ergebnisse. Abgesehen davon, dass in Chrome keine Zeilenumbrüche in der Chrome-Konsole vorhanden sind, wenn Sie nur den Variablennamen eingeben. aber die Variable ist die gleiche. Es ist möglich, mit newlines mit console.log () zu drucken
Shimon Doodkin

0

Ich poste diese Version, da sie die Verwendung von Regex für etwas so Triviales vermeidet.

IMHO Regex ist eine Verschleierung, die als praktischer Witz unter Perl-Entwicklern erstellt wurde. Der Rest der Gemeinde nahm sie ernst und wir zahlen jetzt den Preis, Jahrzehnte später. Verwenden Sie keinen regulären Ausdruck, außer für die Abwärtskompatibilität mit Legacy-Code. Heutzutage gibt es keine Entschuldigung dafür, Code zu schreiben, der nicht sofort von Menschen gelesen und verstanden werden kann. Regex verstößt auf jeder Ebene gegen dieses Prinzip.

Ich habe auch eine Möglichkeit hinzugefügt, das Ergebnis zur aktuellen Seite hinzuzufügen, nicht dass dies gewünscht wurde.

function pretty_css () {
/*
    pre { color: blue; }

*/
}
function css_src (css_fn) {
   var css = css_fn.toString();
   css = css.substr(css.indexOf("/*")+2);
   return css.substr(0,css.lastIndexOf("*/")).trim();
}

function addCss(rule) {
  let css = document.createElement('style');
  css.type = 'text/css';
  if (css.styleSheet) css.styleSheet.cssText = rule; // Support for IE
  else css.appendChild(document.createTextNode(rule)); // Support for the rest
  document.getElementsByTagName("head")[0].appendChild(css);
}

addCss(css_src(pretty_css));

document.querySelector("pre").innerHTML=css_src(pretty_css);
<pre></pre>

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.