Javascript heredoc


109

Мені потрібно щось на зразок heredoc в JavaScript. У вас є ідеї для цього? Мені потрібна функція крос-браузера.

Я знайшов це:

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

Я думаю, що це спрацює для мене. :)


6
Дублікат stackoverflow.com/questions/805107/…, на який є кілька більш детальних відповідей.
Чадвік

4
Додавання "\" змушує мене щоразу нахмуритися. Імхо, відсутність нормального синтаксису для багаторядкових рядків є абсолютно невиправданим. І вони могли додати його в будь-якій версії, але цього не зробили.
Лекс


Сьогодні це робиться з літеральними шаблонами, як показано в можливому дублікаті (оновленої відповіді тут немає).
brasofilo

Відповіді:


77

Спробуйте набір рядків ES6 , ви можете зробити щось подібне

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


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

=> true

Ви можете використовувати цю чудову функцію сьогодні за допомогою 6to5 або TypeScript


2
Це застосовно, якщо ви просто хотіли багаторядкові рядки. Однак, оскільки ви не можете реально змінити символ, який закриває ваш рядок, це насправді не гередок.
Peeyush Kushwaha

3
Як зауваження, оригінальне запитання було задано 5 років тому до появи ES6. Це найкраща практика вперед, оскільки ефективність також краща.
Генрі Ценг

2
@HenryTseng, тож ви припускаєте, що відповіді на це питання повинні відповідати давнім технологіям, які існували 5 років тому? Якщо питання все ще залишається відкритим, тоді варто заслуговувати на користь нових технологій, як вони створені з часом. Таким чином, нові користувачі, що мають те саме питання, можуть знайти тут "неархеологічну" інформацію.
asiby

1
Ні, я коментував, чому це рішення раніше не було більш помітним. Очевидно, що підтримуваний спосіб рухається вперед, якщо немає проблем із сумісністю.
Генрі Ценг

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

Просто замініть "/ * ТУТ" та "ТУТ * /" на вибір слова.


4
чи всі браузери / двигуни повертають коментарі у Function.toString ()? це дуже розумно
gcb

Працює в консолі Chrome
Omn

4
Не вийде, якщо у вас є */гередок із заключним коментарем .
Наріго

2
Я рекомендую використовувати відповідь Нейт Ферреро, оскільки його приклад є більш вишуканим та оптимізованим. Шахта використовує 3 окремі виклики regEx і є більшою доказовою концепцією.
Zv_oDD

1
Дуже розумний ... але ви не можете гарантувати, що це спрацює в майбутньому. Це занадто залежне від впровадження, щоб бути гарною практикою.
П’єр-Олів'є

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. Текст обрізаний на обох кінцях, тому будь-яке додаткове пробіл на будь-якому кінці добре.

Зміни:

02.02.2014 - змінено, щоб взагалі не возитися з прототипом Function і використовувати замість нього ім'я heredoc.

26.05.2017 - оновлений пробіл для відображення сучасних стандартів кодування.


1
Я використовував би тутDoc () як своє ім'я функції, але цей код спрацював чудово, завантажуючи свій дамп журналу 40k рядка в змінну в консолі Chrome
Omn

Навіщо створити екземпляр функції та отримати доступ до застарілого властивості __ proto __? Чому б не просто зробити Function.prototype.str = function () {...}?
Джон Курлак

@JohnKurlak, що ще краще! Я не думаю, що знав, що це можливо, коли я написав відповідь.
Нейт Ферреро

2
@NateFerrero - Чудова відповідь, дякую! Як окрему відповідь додано власне розширення.
Ендрю Чонг

На моєму 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 мають функцію heredoc.

Ви можете оголосити рядки, укладені зворотним галочкою (``), і їх можна розширити через кілька рядків.

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

Ви також можете включити вирази всередині рядків шаблонів. Вони позначені знаком долара та фігурними дужками ( ${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 - для тих, хто бажає використовувати блокові коментарі у своєму гередоку ...

В основному мені потрібні були гередоки 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, і, на жаль (як натякає виділення синтаксису) перший */закінчується загальним коментарем, порушуючи гередок.


Для цієї конкретної мети (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/');
};

і використовувати його, додавши пробіл між коментарями блоку *та /для внутрішнього коментаря, наприклад:

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.
     *-/

якщо ви просто оновите регулярний вираз:

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

А може, ви хочете довільну кількість пробілів замість одного пробілу?

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

2
Класно! Це було відоме обмеження в моєму методі, мені це подобається :)
Нейт Ферреро

8

Ви можете використовувати CoffeeScript , мову, що збирається на JavaScript. Код компілюється один на один в еквівалентний JS, а інтерпретації під час виконання немає.

І звичайно, в ньому є гередоки :)


24
Правильна відповідь - ні. CoffeeScript та EJS можуть використовуватися як пропозиції.
alvincrespo

4
CoffeeScript - правильна відповідь на більшість проблем із JS, з якими я стикався. Якщо ви пишете більше тривіальної кількості JS (і ви цінуєте свій час та енергію), ви зобов'язані цим самим використовувати його.
Брендон

5
Я думаю, що це хороша відповідь, оскільки він пропонує простий спосіб обійти відсутність гередока в JavaScript. Економив мені багато часу.
Стофке

3
Якщо ви просто хочете шматок js, але не хочете мати справу з його написанням: coffeescript.org і скористайтесь кнопкою "Спробуйте Coffeescript".
jcollum

1
Це скоріше відповідь, ніж найвище оцінений, який в основному просто ... "ні". Я ненавиджу такі відповіді.
Метт Флетчер

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, щоб додати його так, як створив Тім Дісней у цій публікації

Зауважте, що цей підхід використовує зворотні посилання як розділовники рядків:

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 дають вам більшість того, що надають традиційні гередоки.

Якщо ви хочете піти на крок далі і використовувати рядок із тегом шаблону, 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.
Дейв Ньютон

що відрізняється? Просто перевірений у Chrome та FF, і я отримую точно такі ж результати. За винятком того, що в Chrome немає нових рядків у консолі Chrome. Якщо ви просто введете ім'я var. але змінна та сама. Можна друкувати новими рядками з console.log ()
Шимон Додкін

0

Я публікую цю версію, оскільки це дозволяє уникнути використання регулярного вираження для чогось такого тривіального.

Регекс IMHO - це запаморочення, яке було створено як практичний жарт серед розробників perl. решта громади сприйняли їх серйозно, і ми тепер платимо ціну через десятки років. не використовуйте регулярні вирази, за винятком відсталої сумісності зі застарілим кодом. У наші дні немає приводу писати код, який не одразу є зрозумілим для людини та зрозумілим. Регекс порушує цей принцип на кожному рівні.

Я також додав спосіб додати результат до поточної сторінки, а не про те, про що вимагали.

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>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.