Javascript heredoc


109

Ho bisogno di qualcosa come heredoc in JavaScript. Hai qualche idea per questo? Ho bisogno di funzionalità cross-browser.

Ho trovato questo:

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

Penso che funzionerà per me. :)


6
Duplicato di stackoverflow.com/questions/805107/… che ha alcune risposte più dettagliate.
Chadwick

4
Dover aggiungere "\" mi fa sempre accigliare. Imho, non avere una sintassi normale per le stringhe multilinea è completamente ingiustificato. E avrebbero potuto aggiungerlo in qualsiasi versione, ma non l'hanno fatto.
Lex


Al giorno d'oggi, questo viene fatto con i letterali del modello come mostrato nel possibile duplicato (non c'è una risposta aggiornata qui).
brasofilo

Risposte:


77

Prova ES6 String Template , puoi fare qualcosa di simile

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


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

=> true

Puoi utilizzare questa fantastica funzionalità oggi con 6to5 o TypeScript


2
Questo è applicabile se desideri solo stringhe multilinea. Tuttavia, poiché non puoi davvero cambiare il simbolo che racchiude la tua stringa, non è proprio ereditario.
Peeyush Kushwaha

3
Come nota, la domanda originale è stata posta 5 anni fa prima che ES6 fosse disponibile. Questa è la migliore pratica da seguire poiché anche le prestazioni sono migliori.
Henry Tseng

2
@HenryTseng, quindi stai suggerendo che le risposte a questa domanda dovrebbero essere adattate alle antiche tecnologie che esistevano 5 anni fa? Se la domanda è ancora aperta, allora merita di sfruttare le nuove tecnologie così come sono state create nel tempo. In questo modo, i nuovi utenti che hanno lo stesso problema possono trovare qui informazioni "non archeologiche".
asiby

1
No, stavo facendo un commento sul motivo per cui quella soluzione non era più prominente in precedenza. Sembra decisamente come il modo supportato per andare avanti se non ci sono problemi di compatibilità.
Henry Tseng

63

No, sfortunatamente JavaScript non supporta niente come heredoc.


12
Lo so ma spero di trovare heredoc hack :)
VeroLom

Qualcosa come i commenti della funzione di analisi (ma non funziona in ie / firefox) =
VeroLom

37

Cosa ne pensi di questo:

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());

Basta sostituire "/ * QUI" e "QUI * /" con una parola a scelta.


4
tutti i browser / motori restituiscono i commenti in Function.toString ()? è molto intelligente
gcb

Funziona nella console di Chrome
Omn

4
Non funzionerà se hai un commento di chiusura */nel tuo heredoc.
Narigo

2
Consiglierei di utilizzare la risposta di Nate Ferrero, poiché il suo è un esempio più raffinato e ottimizzato. Il mio utilizza 3 chiamate regEx separate ed è più una prova di concetto.
Zv_oDD

1
Molto intelligente ... ma non puoi garantire che funzionerà in futuro. È troppo dipendente dall'attuazione per essere una buona pratica.
Pierre-Olivier Vares

33

Basandomi sulla risposta di Zv_oDD, ho creato una funzione simile per un più facile riutilizzo.

Avvertenza: questa è una funzionalità non standard di molti interpreti JS e probabilmente verrà rimossa a un certo punto, ma poiché sto creando uno script da utilizzare solo in Chrome, lo sto usando! Non fare mai affidamento su questo per i siti Web rivolti ai clienti!

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

Uso:

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

Ritorna:

"A test of horrible
Multi-line strings!"

Appunti:

  1. Il testo viene tagliato su entrambe le estremità, quindi qualsiasi spazio bianco aggiuntivo su entrambe le estremità va bene.

modifiche:

2/2/2014 - modificato per non creare problemi con il prototipo della funzione e utilizzare invece il nome heredoc.

26/5/2017 - spazi bianchi aggiornati per riflettere i moderni standard di codifica.


1
Vorrei usare hereDoc () come nome della funzione, ma questo codice ha funzionato correttamente caricando il mio dump del log della riga 40k in una variabile nella console di Chrome
Omn

Perché dovresti creare un'istanza di una funzione e accedere alla proprietà deprecata __ proto __? Perché non eseguire semplicemente Function.prototype.str = function () {...}?
John Kurlak

@JohnKurlak che è ancora meglio! Non credo di essermi reso conto che era possibile quando ho scritto la risposta.
Nate Ferrero

2
@NateFerrero - Ottima risposta, grazie! Aggiunta una mia estensione come risposta separata.
Andrew Cheong

Sul mio Android, nexus 4, con 5.0.1, non funziona più su Chrome. Per qualche motivo, sta eliminando spazi e commenti. Non riesco a capire se questa è un'impostazione, ma è sicuramente dal lato client. Qualche idea per una soluzione alternativa?
MLU

19

A seconda del tipo di motore JS / JS che stai utilizzando (SpiderMonkey, AS3) puoi semplicemente scrivere XML inline, in cui puoi posizionare il testo su più righe, come 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 ha la funzione heredoc.

È possibile dichiarare stringhe racchiuse da back-tick (``) e possono essere espanse su più righe.

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

Puoi anche includere espressioni all'interno di stringhe modello. Questi sono indicati dal segno del dollaro e dalle parentesi graffe ( ${expression}).

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"

Ci sono infatti più funzionalità come Tagged Temple Strings e Raw Strings. Si prega di trovare la documentazione su

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


8

Mi dispiace scrivere una risposta separata per una semplice estensione alla risposta di @NateFerrero , ma non credo che la modifica della sua risposta sia appropriata, quindi per favore vota @NateFerrero se questa risposta ti è stata utile.

tl; dr: per coloro che desiderano utilizzare i commenti di blocco all'interno del proprio heredoc ...

Ho principalmente bisogno di heredoc Javascript per memorizzare un blocco di CSS, ad es

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;
    }
*/});

Come puoi vedere però, mi piace commentare il mio CSS, e purtroppo (come accennato dall'evidenziazione della sintassi) il primo */conclude il commento generale, rompendo l'heredoc.


Per questo scopo specifico (CSS), la mia soluzione alternativa era aggiungere

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

alla catena all'interno di @ NateFerrero's heredoc; in forma completa:

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

e usalo aggiungendo uno spazio tra *e /per i commenti di blocco "interni", in questo modo:

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;
    }
*/});

Il replacesemplicemente trova /* ... * /e rimuove lo spazio per fare /* ... */, preservando così l'eredoc fino al momento della chiamata.


Ovviamente puoi rimuovere completamente i commenti usando

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

Puoi anche supportare i //commenti se li aggiungi alla catena:

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

Inoltre, puoi fare qualcosa di diverso dal singolo spazio tra *e /, come -:

    /**
     * Nuke rounded corners.
     *-/

se aggiorni la regex in modo appropriato:

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

O forse desideri una quantità arbitraria di spazi bianchi invece di un singolo spazio?

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

2
Freddo! Questa era una limitazione nota del mio metodo, mi piace :)
Nate Ferrero

8

Potresti usare CoffeeScript , un linguaggio che compila fino a JavaScript. Il codice compila uno a uno nell'equivalente JS e non c'è interpretazione in fase di esecuzione.

E, naturalmente, ha ereditari :)


24
La risposta corretta è no. CoffeeScript ed EJS potrebbero essere usati come suggerimenti.
alvincrespo

4
CoffeeScript è la risposta corretta alla maggior parte dei problemi di JS che ho riscontrato. Se scrivi più di una banale quantità di JS (e apprezzi il tuo tempo e la tua energia) devi a te stesso per usarlo.
Brandon

5
Penso che questa sia una buona risposta in quanto fornisce un modo semplice per aggirare l'assenza di heredoc in javascript. Mi ha fatto risparmiare molto tempo.
Stofke

3
Se vuoi solo un pezzo di js ma non vuoi occuparti di scriverlo effettivamente: coffeescript.org e usa il pulsante "Prova Coffeescript".
jcollum

1
Questa è più una risposta rispetto a quella con il punteggio più alto, che in pratica è solo ... "no". Odio questo tipo di risposte.
Matt Fletcher

7

ES5 e versioni precedenti

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

ES6 e versioni successive

`some random
multi line
text here`

risultato

some random
multi line
text here

meglio semplicemente rispondere
Benjamin

1
La cosa vecchio stile è un trucco incredibilmente brutale: /
Shayne

1

Puoi usare Sweet.js Macro per aggiungerlo in questo modo, come creato da Tim Disney in questo post

Nota che questo approccio utilizza invece i backtick come delimitatori di stringa:

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

Come altri hanno già detto, le stringhe di template ES6 ti danno la maggior parte di ciò che forniscono gli heredoc tradizionali.

Se vuoi fare un ulteriore passo avanti e utilizzare una stringa modello con tag, theredocè una bella funzione di utilità che ti consente di farlo:

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

Se hai a portata di mano dell'html e di jQuery e la stringa è HTML valido, questo può essere utile:

<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>

Se il testo ha commenti "<! - ->" nel mezzo, funziona anche, ma una parte del testo potrebbe essere visibile. Ecco il violino: 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
}

esempio

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));

con cache: - crea una semplice funzione modello e salva la funzione: (la seconda volta funziona velocemente)

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
Risultati abbastanza diversi in FF e Chrome.
Dave Newton

cosa c'è di diverso? Appena testato in Chrome e FF e ottengo esattamente gli stessi risultati. Tranne che in Chrome non ci sono nuove righe nella console di Chrome Se digiti solo il nome var. ma la variabile è la stessa. È possibile stampare con le nuove righe con console.log ()
Shimon Doodkin

0

Sto postando questa versione in quanto evita l'uso di regex per qualcosa di così banale.

La regex IMHO è un offuscamento che è stato creato come uno scherzo pratico tra gli sviluppatori di Perl. il resto della comunità li ha presi sul serio e ora ne paghiamo il prezzo, decenni dopo. non utilizzare regex, ad eccezione della compatibilità con le versioni precedenti con il codice legacy. non ci sono scuse in questi giorni per scrivere codice che non sia immediatamente leggibile e comprensibile dall'uomo. regex viola questo principio a tutti i livelli.

Ho anche aggiunto un modo per aggiungere il risultato alla pagina corrente, non che sia stato richiesto.

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>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.