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.