Javascript heredoc

109

Saya butuh sesuatu seperti heredoc di JavaScript. Apakah Anda punya ide untuk ini? Saya membutuhkan fungsionalitas lintas browser.

Aku menemukan ini:

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

Saya pikir itu akan berhasil untuk saya. :)

VeroLom
sumber
6
Duplikat stackoverflow.com/questions/805107/… yang memiliki beberapa jawaban yang lebih rinci.
Chadwick
4
Harus menambahkan "\" membuatku cemberut setiap saat. Imho, tidak memiliki sintaks normal untuk string multiline sama sekali tidak dapat dibenarkan. Dan mereka dapat menambahkannya pada versi tertentu, tetapi mereka tidak melakukannya.
Lex
1
Kemungkinan duplikat dari Membuat string multiline di JavaScript
brasofilo
Saat ini, ini dilakukan dengan template literal seperti yang ditunjukkan pada kemungkinan duplikat (tidak ada jawaban yang diperbarui di sini).
brasofilo

Jawaban:

77

Coba ES6 String Template , Anda dapat melakukan sesuatu seperti

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


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

=> true

Anda dapat menggunakan fitur hebat ini hari ini dengan 6to5 atau TypeScript

mko
sumber
2
Ini berlaku jika Anda hanya menginginkan string multi-baris. Namun, karena Anda tidak dapat benar-benar mengubah simbol yang membungkus string Anda, itu tidak benar-benar heredoc.
Peeyush Kushwaha
3
Sekadar catatan, pertanyaan awal ditanyakan 5 tahun lalu sebelum ES6 tersedia. Ini adalah praktik terbaik untuk maju karena performa juga lebih baik.
Henry Tseng
2
@HenryTseng, jadi apakah Anda menyarankan agar jawaban atas pertanyaan ini harus disesuaikan dengan teknologi kuno yang ada 5 tahun yang lalu? Jika pertanyaannya masih terbuka, maka layak untuk memanfaatkan teknologi baru seperti yang diciptakan dari waktu ke waktu. Dengan begitu, pengguna baru yang memiliki masalah yang sama dapat menemukan informasi "non-arkeologis" di sini.
asiby
1
Tidak, saya membuat komentar tentang mengapa solusi itu tidak lebih menonjol sebelumnya. Sepertinya cara yang didukung bergerak maju jika tidak ada masalah kompatibilitas.
Henry Tseng
63

Tidak, sayangnya JavaScript tidak mendukung hal seperti heredoc.

Andrew Hare
sumber
12
Saya tahu, tetapi saya berharap menemukan
retasan
Sesuatu seperti komentar fungsi parse (tetapi tidak berfungsi di ie / firefox) =
VeroLom
37

Bagaimana dengan ini:

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

Cukup ganti "/ * HERE" dan "HERE * /" dengan kata pilihan.

Zv_oDD
sumber
4
apakah semua browser / mesin mengembalikan komentar di Function.toString ()? itu sangat pintar
gcb
Berfungsi di konsol Chrome
Omn
4
Tidak akan berhasil jika Anda memiliki komentar penutup */di heredoc Anda.
Narigo
2
Saya akan merekomendasikan menggunakan jawaban Nate Ferrero, karena jawabannya adalah contoh yang lebih halus dan dioptimalkan. Mine menggunakan 3 panggilan regEx terpisah dan lebih merupakan bukti konsep.
Zv_oDD
1
Sangat pintar ... tapi Anda tidak bisa menjamin itu akan berhasil di masa depan. Ini terlalu bergantung pada implementasi untuk menjadi praktik yang baik.
Pierre-Olivier Vares
33

Berdasarkan jawaban Zv_oDD, saya membuat fungsi serupa agar lebih mudah digunakan kembali.

Peringatan: Ini adalah fitur non-standar dari banyak interpreter JS, dan mungkin akan dihapus pada suatu saat, tetapi karena saya membuat skrip untuk hanya digunakan di Chrome, saya menggunakannya! Jangan pernah mengandalkan ini untuk situs web yang berhadapan dengan klien!

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

Menggunakan:

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

Pengembalian:

"A test of horrible
Multi-line strings!"

Catatan:

  1. Teks dipangkas di kedua ujungnya, jadi setiap spasi tambahan di kedua ujung tidak apa-apa.

Editan:

2/2/2014 - diubah menjadi tidak main-main dengan prototipe Fungsi sama sekali dan menggunakan nama heredoc sebagai gantinya.

26/5/2017 - spasi yang diperbarui untuk mencerminkan standar pengkodean modern.

Nate Ferrero
sumber
1
Saya akan menggunakan hereDoc () sebagai nama fungsi saya, tetapi kode ini berfungsi dengan baik saat memuat dump log baris 40k saya ke variabel di konsol Chrome
Omn
Mengapa Anda membuat instance dari suatu fungsi dan mengakses properti yang tidak digunakan lagi __ proto __? Mengapa tidak hanya melakukan Function.prototype.str = function () {...}?
John Kurlak
@JohnKurlak itu lebih baik! Saya tidak berpikir saya menyadari bahwa itu mungkin ketika saya menulis jawabannya.
Nate Ferrero
2
@NateFerrero - Jawaban yang luar biasa, terima kasih! Menambahkan ekstensi saya sendiri sebagai jawaban terpisah.
Andrew Cheong
Di Android saya, nexus 4, menjalankan 5.0.1, ini tidak lagi berfungsi di Chrome. Untuk beberapa alasan, ini menghapus spasi dan komentar. Saya tidak tahu apakah ini adalah pengaturan, tetapi pasti di sisi klien. Ada ide untuk mengatasinya?
MLU
19

Bergantung pada jenis mesin JS / JS yang Anda jalankan (SpiderMonkey, AS3), Anda cukup menulis XML sebaris, di mana Anda dapat menempatkan teks pada beberapa baris, seperti heredoc:

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

console.log(xml.toXMLString())
console.log(xml.toString()) // just gets the content
Dave Stewart
sumber
13

String Template ES6 memiliki fitur heredoc.

Anda dapat mendeklarasikan string yang diapit oleh tanda centang balik (``) dan dapat diperluas melalui beberapa baris.

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

Anda juga dapat menyertakan ekspresi di dalam Template Strings. Ini ditunjukkan oleh tanda Dolar dan tanda kurung kurawal ( ${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"

Sebenarnya ada lebih banyak fitur seperti Tagged Temple Strings dan Raw Strings di dalamnya. Temukan dokumentasi di

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

Charlie
sumber
8

Saya merasa tidak enak menulis jawaban terpisah hanya untuk perpanjangan dari jawaban @ NateFerrero , tetapi saya juga merasa mengedit jawabannya juga tidak sesuai, jadi tolong upvote @NateFerrero jika jawaban ini bermanfaat bagi Anda.

tl; dr — Bagi mereka yang ingin menggunakan komentar blokir di dalam heredoc ...

Saya terutama membutuhkan Javascript heredocs untuk menyimpan satu blok CSS, misalnya

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

Namun seperti yang Anda lihat, saya suka mengomentari CSS saya, dan sayangnya (seperti yang diisyaratkan oleh penyorotan sintaks) yang pertama */mengakhiri keseluruhan komentar, melanggar heredoc.


Untuk tujuan khusus ini (CSS), solusi saya adalah menambahkan

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

ke rantai di dalam @ NateFerrero heredoc; dalam bentuk lengkap:

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

dan menggunakannya dengan menambahkan spasi di antara *dan /untuk komentar blok "dalam", seperti:

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

Yang replacesederhana menemukan /* ... * /dan menghilangkan ruang untuk dibuat /* ... */, dengan demikian melestarikan heredoc sampai dipanggil.


Anda tentu saja dapat menghapus semua komentar menggunakan

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

Anda juga dapat mendukung //komentar jika Anda menambahkannya ke rantai:

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

Selain itu, Anda dapat melakukan sesuatu selain spasi tunggal antara *dan /, seperti -:

    /**
     * Nuke rounded corners.
     *-/

jika Anda hanya memperbarui regex dengan benar:

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

Atau mungkin Anda menginginkan jumlah spasi yang berubah-ubah alih-alih satu spasi?

.replace(/(\/\*[\s\S]*?\*)\s+\//g, '$1/')
                          ^^^
Andrew Cheong
sumber
2
Keren! Itu adalah batasan yang diketahui dengan metode saya, saya menyukainya :)
Nate Ferrero
8

Anda dapat menggunakan CoffeeScript , bahasa yang dikompilasi ke JavaScript. Kode mengkompilasi satu-ke-satu ke dalam JS yang setara, dan tidak ada interpretasi pada waktu proses.

Dan tentu saja, itu memiliki heredocs :)

Jakob
sumber
24
Jawaban yang benar adalah tidak. CoffeeScript dan EJS dapat digunakan sebagai saran.
alvincrespo
4
CoffeeScript adalah jawaban yang benar untuk sebagian besar masalah JS yang saya temui. Jika Anda menulis lebih dari jumlah JS yang sepele (dan Anda menghargai waktu dan energi Anda), Anda berhutang pada diri Anda sendiri untuk menggunakannya.
Brandon
5
Saya pikir ini adalah jawaban yang bagus karena memberikan cara mudah untuk menghindari tidak adanya heredoc di javascript. Menyelamatkan saya banyak waktu.
Stofke
3
Jika Anda hanya ingin sepotong js tetapi tidak ingin berurusan dengan benar-benar menulisnya: coffeescript.org dan gunakan tombol "Coba Coffeescript".
jcollum
1
Ini lebih merupakan jawaban daripada yang berperingkat tertinggi, yang pada dasarnya hanya ... "tidak". Saya benci jawaban seperti itu.
Matt Fletcher
7

ES5 dan versi sebelumnya

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

ES6 dan versi yang lebih baru

`some random
multi line
text here`

hasil

some random
multi line
text here
Ga1der
sumber
jawaban sederhana terbaik
Benjamin
1
Gaya lama adalah peretasan yang sangat brutal: /
Shayne
1

Anda dapat menggunakan Sweet.js Macros untuk menambahkannya seperti itu, seperti yang dibuat oleh Tim Disney di posting ini

Perhatikan bahwa pendekatan ini menggunakan backticks sebagai pemisah string sebagai gantinya:

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`
Brad Parks
sumber
1

Seperti yang dikatakan orang lain, string template ES6 memberi Anda sebagian besar dari apa yang disediakan oleh heredocs tradisional.

Jika Anda ingin melangkah lebih jauh dan menggunakan string template yang diberi tag, theredocadalah fungsi utilitas bagus yang memungkinkan Anda melakukan ini:

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.
  `)
}
Neall
sumber
0

Jika Anda memiliki beberapa html dan jQuery dan stringnya adalah HTML yang valid, ini mungkin berguna:

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

Jika teks memiliki komentar "<! - ->" di antaranya, ini juga berfungsi, tetapi sebagian teks mungkin terlihat. Ini biolanya: https://jsfiddle.net/hr6ar152/1/

Max Oriola
sumber
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
}

contoh

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

dengan cache: - buat fungsi template sederhana, dan simpan fungsinya: (kedua kalinya bekerja cepat)

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)
Shimon Doodkin
sumber
1
Hasil yang cukup berbeda di FF dan Chrome.
Dave Newton
apa bedanya? Baru saja diuji di Chrome dan FF dan saya mendapatkan hasil yang persis sama. Kecuali bahwa di Chrome tidak ada baris baru di Konsol Chrome Jika Anda hanya mengetik nama var. tetapi variabelnya sama. Mungkin untuk mencetak dengan baris baru dengan console.log ()
Shimon Doodkin
0

Saya memposting versi ini karena menghindari penggunaan regex untuk sesuatu yang sangat sepele.

IMHO regex adalah obfuscation yang dibuat sebagai lelucon praktis di antara pengembang perl. komunitas lainnya menanggapinya dengan serius dan kami sekarang harus menanggung akibatnya, puluhan tahun kemudian. jangan gunakan regex, kecuali untuk kompatibilitas mundur dengan kode lama. tidak ada alasan akhir-akhir ini untuk menulis kode yang tidak langsung dapat dibaca dan dimengerti oleh manusia. regex melanggar prinsip ini di setiap level.

Saya juga telah menambahkan cara untuk menambahkan hasil ke halaman ini, bukan yang diminta.

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>

tidak tersinkronisasi
sumber