Javascript heredoc


109

ฉันต้องการบางอย่างเช่น heredoc ใน JavaScript คุณมีความคิดเกี่ยวกับเรื่องนี้หรือไม่? ฉันต้องการฟังก์ชันข้ามเบราว์เซอร์

ฉันพบสิ่งนี้:

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

ฉันคิดว่ามันจะได้ผลสำหรับฉัน :)


6
สำเนาstackoverflow.com/questions/805107/…ซึ่งมีคำตอบที่ละเอียดกว่านี้
Chadwick

4
การต้องเพิ่ม "\" ทำให้ฉันขมวดคิ้วทุกครั้ง อิมโฮการไม่มีไวยากรณ์ปกติสำหรับสตริงหลายบรรทัดถือว่าไม่ยุติธรรมอย่างสิ้นเชิง และพวกเขาสามารถเพิ่มในเวอร์ชันใดก็ได้ แต่ไม่ได้เพิ่ม
Lex


ปัจจุบันสิ่งนี้ทำได้ด้วยตัวอักษรเทมเพลตตามที่แสดงในการทำซ้ำที่เป็นไปได้ (ไม่มีคำตอบที่อัปเดตที่นี่)
brasofilo

คำตอบ:


77

ลองใช้เทมเพลตสตริง ES6คุณสามารถทำสิ่งต่างๆเช่น

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


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

=> true

คุณสามารถใช้คุณสมบัติที่ยอดเยี่ยมนี้ได้แล้ววันนี้ด้วย6to5หรือTypeScript


2
สิ่งนี้ใช้ได้หากคุณต้องการเพียงแค่สตริงหลายบรรทัด อย่างไรก็ตามเนื่องจากคุณไม่สามารถเปลี่ยนสัญลักษณ์ที่ล้อมรอบสตริงของคุณได้จริงๆจึงไม่ใช่ heredoc
Peeyush Kushwaha

3
เช่นเดียวกับหมายเหตุคำถามเดิมถูกถามเมื่อ 5 ปีก่อนก่อนที่ ES6 จะพร้อมใช้งาน นี่เป็นแนวทางปฏิบัติที่ดีที่สุดในการก้าวไปข้างหน้าเนื่องจากประสิทธิภาพก็ดีขึ้นเช่นกัน
Henry Tseng

2
@HenryTseng คุณแนะนำว่าคำตอบของคำถามนี้ควรปรับให้เหมาะกับเทคโนโลยีโบราณที่มีอยู่เมื่อ 5 ปีก่อนหรือไม่? หากคำถามยังคงเปิดอยู่ก็สมควรที่จะใช้ประโยชน์จากเทคโนโลยีใหม่ ๆ ตามที่สร้างขึ้นเมื่อเวลาผ่านไป ด้วยวิธีนี้ผู้ใช้ใหม่ที่มีปัญหาเดียวกันสามารถค้นหาข้อมูล "ไม่ใช่โบราณคดี" ได้ที่นี่
asiby

1
ไม่ฉันกำลังแสดงความคิดเห็นว่าเหตุใดวิธีการแก้ปัญหานั้นจึงไม่โดดเด่นกว่าก่อนหน้านี้ ดูเหมือนว่าวิธีที่รองรับจะก้าวไปข้างหน้าอย่างแน่นอนหากไม่มีปัญหาความเข้ากันได้ใด ๆ
Henry Tseng

63

ไม่น่าเสียดายที่ JavaScript ไม่รองรับอะไรเช่น heredoc


12
ฉันรู้ แต่ฉันหวังว่าจะพบ heredoc hack :)
VeroLom

บางอย่างเช่นความคิดเห็นของฟังก์ชันแยกวิเคราะห์ (แต่ใช้ไม่ได้ใน ie / firefox) =
VeroLom

37

แล้วสิ่งนี้ล่ะ:

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

เพียงแค่แทนที่ "/ * HERE" และ "HERE * /" ด้วยคำที่ต้องการ


4
เบราว์เซอร์ / เอนจิ้นทั้งหมดแสดงความคิดเห็นใน Function.toString () หรือไม่ ฉลาดมาก
gcb

ทำงานในคอนโซลของ Chrome
OMN

4
จะไม่ได้ผลหากคุณมีความคิดเห็นปิด*/ใน heredoc ของคุณ
Narigo

2
ฉันขอแนะนำให้ใช้คำตอบของ Nate Ferrero เนื่องจากเป็นตัวอย่างที่ละเอียดและเหมาะสมกว่า Mine ใช้การเรียก regEx แยกกัน 3 ครั้งและเป็นหลักฐานยืนยันแนวคิด
Zv_oDD

1
ฉลาดมาก ... แต่คุณไม่สามารถรับประกันได้ว่าจะใช้งานได้ในอนาคต มันขึ้นอยู่กับการนำไปใช้มากเกินไปที่จะเป็นแนวทางปฏิบัติที่ดี
Pierre-Olivier Vares

33

จากคำตอบของ Zv_oDD ฉันได้สร้างฟังก์ชันที่คล้ายกันเพื่อการนำกลับมาใช้ใหม่ได้ง่ายขึ้น

คำเตือน:นี่เป็นคุณสมบัติที่ไม่ได้มาตรฐานของล่าม JS จำนวนมากและอาจจะถูกลบออกในบางจุด แต่เนื่องจากฉันกำลังสร้างสคริปต์เพื่อใช้ใน Chrome เท่านั้นฉันจึงใช้มัน! ไม่เคยพึ่งพานี้สำหรับเว็บไซต์ของลูกค้าที่หันหน้าไป!

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

ใช้:

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

ผลตอบแทน:

"A test of horrible
Multi-line strings!"

หมายเหตุ:

  1. ข้อความถูกตัดออกที่ปลายทั้งสองด้านดังนั้นการเว้นวรรคเพิ่มเติมใด ๆ ที่ปลายด้านใดด้านหนึ่งจึงใช้ได้

การแก้ไข:

2/2/2557 - เปลี่ยนเป็นไม่ยุ่งกับ Function ต้นแบบเลยและใช้ชื่อ heredoc แทน

26/5/2017 - ปรับปรุงช่องว่างเพื่อให้สอดคล้องกับมาตรฐานการเข้ารหัสที่ทันสมัย


1
ผมจะใช้ hereDoc () เป็นชื่อของฟังก์ชั่นของฉัน แต่รหัสนี้ทำงานโหลดปรับการถ่ายโอนข้อมูลเข้าสู่ระบบ 40k สายของฉันเป็นตัวแปรในคอนโซลของ Chrome
OMN

เหตุใดคุณจึงสร้างอินสแตนซ์ของฟังก์ชันและเข้าถึงคุณสมบัติที่เลิกใช้แล้ว __ proto __ ทำไมไม่ทำแค่ Function.prototype.str = function () {... }
John Kurlak

@JohnKurlak ที่ดียิ่งขึ้น! ฉันไม่คิดว่าฉันรู้ตัวว่าเป็นไปได้เมื่อฉันเขียนคำตอบ
Nate Ferrero

2
@NateFerrero - คำตอบที่ยอดเยี่ยมขอบคุณ! เพิ่มส่วนขยายของฉันเองเป็นคำตอบแยกต่างหาก
Andrew Cheong

ใน Android, nexus 4 ของฉันซึ่งใช้งาน 5.0.1 จะใช้งานบน Chrome ไม่ได้อีกต่อไป ด้วยเหตุผลบางประการการลบช่องว่างและความคิดเห็น ฉันไม่สามารถเข้าใจได้ว่านี่เป็นการตั้งค่าหรือไม่ แต่แน่นอนอยู่ในฝั่งไคลเอ็นต์ มีแนวคิดสำหรับวิธีแก้ปัญหาหรือไม่?
MLU

19

ขึ้นอยู่กับรสชาติของเครื่องยนต์ JS / JS ที่คุณใช้อยู่ (SpiderMonkey, AS3) คุณสามารถเขียน XML แบบอินไลน์ซึ่งคุณสามารถวางข้อความในหลายบรรทัดเช่น 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มีคุณลักษณะ heredoc

คุณสามารถประกาศสตริงที่ล้อมรอบด้วย back-tick (``) และสามารถขยายได้หลายบรรทัด

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

คุณยังสามารถรวมนิพจน์ไว้ใน Template Strings สิ่งเหล่านี้ระบุด้วยเครื่องหมายดอลลาร์และวงเล็บปีกกา ( ${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"

ในความเป็นจริงมีคุณสมบัติอื่น ๆ เช่น Tagged Temple Strings และ Raw Strings โปรดดูเอกสารที่

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


8

ฉันรู้สึกแย่ที่เขียนคำตอบแยกต่างหากสำหรับเพียงส่วนขยายของคำตอบของ @NateFerreroแต่ฉันไม่รู้สึกว่าการแก้ไขคำตอบของเขานั้นเหมาะสมเช่นกันดังนั้นโปรดโหวตให้ @NateFerrero หากคำตอบนี้มีประโยชน์กับคุณ

tl; dr - สำหรับผู้ที่ต้องการใช้บล็อกความคิดเห็นภายใน heredoc ...

ฉันต้องการ heredocs Javascript เป็นหลักในการจัดเก็บบล็อกของ CSS เช่น

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

อย่างไรก็ตามอย่างที่คุณเห็นฉันชอบแสดงความคิดเห็น CSS ของฉันและน่าเสียดาย (ตามคำแนะนำโดยการเน้นไวยากรณ์) ในตอนแรก*/ทำให้ความคิดเห็นโดยรวมจบลงซึ่งเป็นการทำลาย heredoc


เพื่อวัตถุประสงค์เฉพาะนี้ (CSS) วิธีแก้ปัญหาของฉันคือเพิ่ม

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

ไปที่โซ่ภายใน @ NateFerrero's heredoc; ในรูปแบบที่สมบูรณ์:

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

และใช้โดยเพิ่มช่องว่างระหว่าง*และ/สำหรับบล็อกความคิดเห็น "inner" ดังนี้:

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

replaceก็พบ/* ... * /และลบพื้นที่ที่จะทำ/* ... */ดังนั้นการรักษา heredoc จนเรียกว่า


แน่นอนคุณสามารถลบความคิดเห็นทั้งหมดโดยใช้

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

นอกจากนี้คุณยังสามารถสนับสนุน//ความคิดเห็นได้หากคุณเพิ่มลงในห่วงโซ่:

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

นอกจากนี้คุณสามารถทำอย่างอื่นนอกเหนือจากช่องว่างเดียวระหว่าง*และ/เช่น-:

    /**
     * Nuke rounded corners.
     *-/

หากคุณเพิ่งอัปเดต regex อย่างเหมาะสม:

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

หรือบางทีคุณอาจต้องการเว้นวรรคตามจำนวนที่กำหนดแทนการเว้นวรรคเดียว?

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

2
เย็น! นั่นเป็นข้อ จำกัด ที่ทราบกันดีกับวิธีการของฉันฉันชอบมัน :)
Nate Ferrero

8

คุณสามารถใช้CoffeeScriptซึ่งเป็นภาษาที่รวบรวมลงใน JavaScript โค้ดจะรวบรวมแบบตัวต่อตัวเป็น JS ที่เทียบเท่าและไม่มีการตีความที่รันไทม์

และแน่นอนมันมีพันธุกรรม :)


24
คำตอบที่ถูกต้องคือไม่ สามารถใช้ CoffeeScript และ EJS เป็นคำแนะนำได้
alvincrespo

4
CoffeeScript เป็นคำตอบที่ถูกต้องสำหรับปัญหา JS ส่วนใหญ่ที่ฉันพบ หากคุณเขียน JS มากกว่าจำนวนเล็กน้อย (และคุณให้ความสำคัญกับเวลาและพลังงานของคุณ) คุณก็ต้องใช้มัน
Brandon

5
ฉันคิดว่านี่เป็นคำตอบที่ดีเนื่องจากเป็นวิธีง่ายๆในการหลีกเลี่ยงการไม่มี heredoc ในจาวาสคริปต์ ช่วยฉันประหยัดเวลาได้มาก
Stofke

3
หากคุณต้องการเพียงแค่ js จำนวนหนึ่ง แต่ไม่ต้องการจัดการกับการเขียนจริงๆ: coffeescript.orgและใช้ปุ่ม "ลองใช้ Coffeescript"
jcollum

1
นี่เป็นคำตอบมากกว่าคำตอบที่ได้รับคะแนนสูงสุดซึ่งโดยพื้นฐานแล้วก็แค่ ... "ไม่" ฉันเกลียดคำตอบแบบนั้น
Matt Fletcher

7

ES5 และเวอร์ชันก่อนหน้า

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

ES6 และเวอร์ชันที่ใหม่กว่า

`some random
multi line
text here`

ผลลัพธ์

some random
multi line
text here

คำตอบที่ดีที่สุด
เบนจามิน

1
รูปแบบเก่าคือการแฮ็กที่โหดร้ายอย่างไม่น่าเชื่อ: /
Shayne

1

คุณสามารถใช้ Sweet.js Macros เพื่อเพิ่มได้ตามที่ Tim Disney สร้างไว้ในโพสต์นี้

โปรดทราบว่าวิธีนี้ใช้ backticks เป็นตัวคั่นสตริงแทน:

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

ตามที่คนอื่น ๆ กล่าวไว้สตริงเทมเพลต ES6 ให้สิ่งที่ heredocs แบบดั้งเดิมมอบให้คุณได้มากที่สุด

หากคุณต้องการก้าวไปอีกขั้นและใช้สตริงเทมเพลตที่ติดแท็กtheredocเป็นฟังก์ชันยูทิลิตี้ที่ดีที่ให้คุณทำสิ่งนี้:

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

หากคุณมี html และ jQuery อยู่ในมือและสตริงเป็น HTML ที่ถูกต้องสิ่งนี้อาจมีประโยชน์:

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

หากข้อความมีความคิดเห็น "<! - ->" อยู่ระหว่างนั้นก็ใช้ได้เช่นกัน แต่อาจมองเห็นบางส่วนของข้อความได้ นี่คือซอ: 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
}

ตัวอย่าง

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

ด้วยแคช: - สร้างฟังก์ชันเทมเพลตอย่างง่ายและบันทึกฟังก์ชัน: (ครั้งที่สองทำงานเร็ว)

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
ผลลัพธ์ที่แตกต่างกันมากใน FF และ Chrome
Dave Newton

ต่างกันอย่างไร เพิ่งทดสอบใน Chrome และ FF และได้ผลลัพธ์ที่เหมือนกันทุกประการ ยกเว้นว่าใน Chrome จะไม่มีการขึ้นบรรทัดใหม่ในคอนโซลของ Chrome หากคุณเพียงแค่พิมพ์ชื่อ var แต่ตัวแปรเหมือนกัน สามารถพิมพ์ขึ้นบรรทัดใหม่ด้วย console.log ()
Shimon Doodkin

0

ฉันกำลังโพสต์เวอร์ชันนี้เนื่องจากหลีกเลี่ยงการใช้ regex สำหรับบางสิ่งที่ไม่สำคัญ

IMHO regex เป็นความสับสนที่สร้างขึ้นเพื่อเป็นเรื่องตลกที่ใช้งานได้จริงในหมู่นักพัฒนา perl ส่วนที่เหลือของชุมชนให้ความสำคัญกับพวกเขาและตอนนี้เราจ่ายราคาในหลายทศวรรษต่อมา อย่าใช้ regex ยกเว้นการใช้ฐานข้อมูลย้อนหลังด้วยรหัสเดิม ทุกวันนี้ไม่มีข้อแก้ตัวในการเขียนโค้ดที่มนุษย์ไม่สามารถอ่านและเข้าใจได้ในทันที regex ละเมิดหลักการนี้ในทุกระดับ

ฉันได้เพิ่มวิธีการเพิ่มผลลัพธ์ลงในหน้าปัจจุบันไม่ใช่ที่ขอ

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>

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.