JSFiddle - React, Tailwind, and code Playground

by disfated

HTML

<textarea id="pattern" placeholder="Шаблон" autofocus="">а((белые|(странные&зеленые))облака&летят&прыгают)в голубой вышине</textarea>
<textarea id="output" placeholder="Результат"></textarea>

CSS

html, body {
    height: 100%;
}

* {
    box-sizing: border-box;
}

body {
    background: #DEDAD3;
    background: radial-gradient(ellipse at center, #EDECE9 0%,#CDC4B7 100%);
    font-family: sans-serif;
    font-size: 20px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: stretch;
    margin: 0;
    padding: 10px 4%;
}

input, textarea {
    font-family: PT Mono, monospace;
    font-size: 16px;
    line-height: normal;
    outline: none;
    border-radius: 2px;
    background: #faf9f6;
    color: #7E7469;
    width: 100%;
    padding: 0.5em 0.5em 0.5em 0.5em;
    margin: 0;
    border: solid 1px #aaa;
    border-bottom-color: #bbb;
    border-top-color: #999;
    box-shadow: 0 1px 0 rgba(0,0,0,0.1) inset, 0 0 3px rgba(0,0,0,0.05) inset, 0 1px 0 rgba(255,255,255,0.7);
}

input::-webkit-input-placeholder,
textarea::-webkit-input-placeholder {
    color: #D8D3CE;
}

input:focus,
textarea:focus {
    background: #fff;
}

#output {
    margin-top: 5px;
}
}

JavaScript

/*
Built with PEG.js (http://pegjs.majda.cz/)

Grammar:

{

Array.prototype.flatten = function() {
  
  var r = [];

  (function iterate(arr) {
    for (var v, i = 0, l = arr.length; i < l; i++) {
      Array.isArray(v = arr[i]) ? iterate(v) : r.push(v);
    }
  })(this);

  return r;

};

var append = function(arr, str) {
  var i = arr.length;
  str = String(str);
  while (i--) arr[i] += str;
  return arr;
};

var multiply = function(arr, set) {
  var clone = arr.concat(), i, n = set.length;
  arr.length = 0;
  for (i = 0; i < n; i++) {
    arr.push.apply(arr, append(clone.concat(), set[i]));
  }
};

var permute = function(set) {
  var perms = [];
  var used = [];
  function p(set) {
    var i, ch;
    for (i = 0; i < set.length; i++) {
      ch = set.splice(i, 1)[0];
      used.push(ch);
      if (set.length == 0) {
        perms.push(used.slice().join(' '));
      }
      p(set);
      set.splice(i, 0, ch);
      used.pop();
    }
    return perms;
  }
  return p(set);
};

var expression = function(list) {
  return '{' + list.map(function(exp) { return Array.isArray(exp) ? '[' + exp.join(',') + ']' : String(exp); }).join('') + '}';
};

var expression = function(list) {
  var variants = [ '' ], exp;
  if (!Array.isArray(list)) return list;
  while (exp = list.shift()) Array.isArray(exp) ? multiply(variants, exp) : append(variants, exp);
  return variants.length > 1 ? variants : variants[0];
}

}


start
  = a:expression b:("\n" e:expression { return e })* { b.unshift(a); return b.flatten().join(""); }

expression
  = a:(group / [^\n])* { return expression(a) }

group
  = "(" g:( or_expression / and_expression ) ")" { return g }

or_expression
  = a:or_literal b:( "|" a:or_literal { return a } )+ { b.unshift(a); return b.flatten(); }

or_literal
  = a:(group / [^|)\n])+ { return expression(a) }

and_expression
  = a:and_literal b:( "&" c:and_literal { return c } )+ { b.unshift(a); return permute(b.flatten()); }

and_literal
  = a:(group / [^&)\n])+ { return...