рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдкрд╛рд░реНрд╕рд░реНрд╕ рдХреИрд╕реЗ рд▓рд┐рдЦреЗрдВ

... рдЕрд░реНрдерд╛рддреН, рд╕рд░рд▓ рд▓реЛрдЧреЛрдВ рд╕реЗ рдЬрдЯрд┐рд▓ рдкрд╛рд░реНрд╕рд░ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рдХреЗ рдмрд╣реБрдд рдЬрдЯрд┐рд▓ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдПрд▓рдПрд▓ рдкрд╛рд░реНрд╕рд░ рдХреИрд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИред рдХрднреА-рдХрднреА, рдХреБрдЫ рд╕рд░рд▓, рдХреБрдЫ XML-рдЬреИрд╕реА рд╕рдВрд░рдЪрдирд╛ рдпрд╛ рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреЗ рдбреЗрдЯрд╛ URL рдХреЗ рд▓рд┐рдП рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдФрд░ рдлрд┐рд░ рдЖрдорддреМрд░ рдкрд░ рдпрд╛ рддреЛ рдХреЛрдбрд┐рдВрдЧ рд╣рд╛рд░реНрдб-рдЯреВ-рд░реАрдб рдХреЛрдб рд╣реЛрддрд╛ рд╣реИ рдпрд╛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдФрд░ рднреА рдЬрдЯрд┐рд▓ рдФрд░ рдореБрд╢реНрдХрд┐рд▓ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдкрд░ рдирд┐рд░реНрднрд░рддрд╛ рд╣реЛрддреА рд╣реИред рдпрд╣рд╛рдБ рдореИрдВ рдХрдИ рдЬрд╛рдиреЗ-рдорд╛рдиреЗ рд╡рд┐рдЪрд╛рд░реЛрдВ (рдЬрд┐рдирдореЗрдВ рд╕реЗ рдХреБрдЫ Habr├й рдкрд░ рдЖрдпрд╛ рдерд╛) рдХреЛ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдмрддрд╛рддрд╛ рд╣реВрдВ рдХрд┐ рдХреЛрдб рдХреЗ рдмрд╣реБрдд рдХрдо рд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ рд░рд╣рддреЗ рд╣реБрдП рд╕рд░рд▓ рдФрд░ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдлреА рдЬрдЯрд┐рд▓ рдкрд╛рд░реНрд╕рд░ рдХреИрд╕реЗ рд▓рд┐рдЦреЗрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореИрдВ рдПрдХ XML- рдЬреИрд╕реА рд╕рдВрд░рдЪрдирд╛ рдкрд╛рд░реНрд╕рд░ рд▓рд┐рдЦреВрдВрдЧрд╛ред рдФрд░ рд╣рд╛рдВ, рдореИрдВ рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣рд╛рдВ рдПрдХ рддрд╕реНрд╡реАрд░ рдирд╣реАрдВ рдбрд╛рд▓реВрдВрдЧрд╛ред рд▓реЗрдЦ рдореЗрдВ рдХреЛрдИ рдЪрд┐рддреНрд░ рдирд╣реАрдВ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдкрдврд╝рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реЛрдЧрд╛ред







рдореБрдЦреНрдп рд╡рд┐рдЪрд╛рд░





рдпрд╣ рдЗрд╕ рддрдереНрдп рдореЗрдВ рдирд┐рд╣рд┐рдд рд╣реИ рдХрд┐ рдЗрдирдкреБрдЯ рдкрд╛рда рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдЯреБрдХрдбрд╝реЗ рдХреЛ рдПрдХ рдЕрд▓рдЧ рдлрд╝рдВрдХреНрд╢рди (рдЪрд▓реЛ рдЗрд╕реЗ "рдкреИрдЯрд░реНрди" рдХрд╣рддреЗ рд╣реИрдВ) рджреНрд╡рд╛рд░рд╛ рдкрд╛рд░реНрд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЗрди рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рдВрдпреЛрдЬрди рд╕реЗ рдЖрдк рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдХрд╛рд░реНрдп рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдЧреНрд░рдВрдереЛрдВ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рддреЛ, рдПрдХ рдкреИрдЯрд░реНрди рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдирд┐рд╖реНрдкрд╛рджрди рд╡рд┐рдзрд┐ рд╣реЛрддреА рд╣реИ рдЬреЛ рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдХрд░рддреА рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рдФрд░ рдХрд╣рд╛рдБ рд╕реЗ рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рд╣реИ рдФрд░ рдпрд╣ рдкрд╛рд░реНрд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╕реНрдерд╛рди рдФрд░ рдЬрд╣рд╛рдБ рдкрд╛рд░реНрд╕рд┐рдВрдЧ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ рд╣реИ:



var digit = { exec: function (str, pos) { var chr = str.charAt(pos); if (chr >= "0" && chr <= "9") return { res: +chr, end: pos + 1}; } };
      
      







рдЕрдм рдбрд┐рдЬрд┐рдЯ рдПрдХ рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдбрд┐рдЬрд┐рдЯ рдкреИрдЯрд░реНрди рд╣реИ рдФрд░ рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:



 assert.deepEqual(digit.exec("5", 0), { res: 5, end: 1 }); assert.deepEqual(digit.exec("Q", 0), void 0);
      
      







рдРрд╕рд╛ рдЗрдВрдЯрд░рдлреЗрд╕ рдХреНрдпреЛрдВ? рдХреНрдпреЛрдВрдХрд┐ JS рдореЗрдВ рдмрд┐рд▓реНрдЯ-рдЗрди RegExp рдХреНрд▓рд╛рд╕ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдмрд╣реБрдд рд╣реА рд╕рдорд╛рди рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╣реИред рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкреИрдЯрд░реНрди рдХреНрд▓рд╛рд╕ рдХрд╛ рдкрд░рд┐рдЪрдп рджреЗрддреЗ рд╣реИрдВ (рдЗрд╕реЗ RegExp рдХреЗ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рдХреЗ рд░реВрдк рдореЗрдВ рджреЗрдЦреЗрдВ) рдЬрд┐рдирдХреЗ рдЙрджрд╛рд╣рд░рдг рдпреЗ рдкреИрдЯрд░реНрди рд╣реЛрдВрдЧреЗ:



 function Pattern(exec) { this.exec = exec; }
      
      







рдлрд┐рд░ рд╣рдо рдХреБрдЫ рд╕рд░рд▓ рдкреИрдЯрд░реНрди рдкреЗрд╢ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдЕрдзрд┐рдХ рдпрд╛ рдХрдо рдЬрдЯрд┐рд▓ рдкрд╛рд░реНрд╕рд░ рдореЗрдВ рдЙрдкрдпреЛрдЧреА рд╣реЛрддреЗ рд╣реИрдВред



рд╕рд░рд▓ рдкреИрдЯрд░реНрди





рд╕рдмрд╕реЗ рд╕рд░рд▓ рдкреИрдЯрд░реНрди txt рд╣реИ - рдпрд╣ рдкрд╛рда рдХреА рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд, рдкреВрд░реНрд╡ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд░реЗрдЦрд╛ рдХреЛ рдкрд╛рд░ рдХрд░рддрд╛ рд╣реИ:



 function txt(text) { return new Pattern(function (str, pos) { if (str.substr(pos, text.length) == text) return { res: text, end: pos + text.length }; }); }
      
      







рдЗрд╕реЗ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:



 assert.deepEqual(txt("abc").exec("abc", 0), { res: "abc", end: 3 }); assert.deepEqual(txt("abc").exec("def", 0), void 0);
      
      







рдпрджрд┐ JS рдХреЗ рдкрд╛рд╕ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдирд┐рд░реНрдорд╛рддрд╛ (C ++ рдореЗрдВ) рд╣реИрдВ, рддреЛ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдкреИрдЯрд░реНрди рдмрдирд╛рдиреЗ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ txt ("abc") рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдХреЛ "abc" рдЫреЛрдЯрд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред



рдлрд┐рд░ рд╣рдо рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХреЗ рдПрдирд╛рд▓реЙрдЧ рдХреЛ рдкреЗрд╢ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдЖрд░рдЬреАрдПрдХреНрд╕ рдХрд╣рддреЗ рд╣реИрдВ:



 function rgx(regexp) { return new Pattern(function (str, pos) { var m = regexp.exec(str.slice(pos)); if (m && m.index === 0) return { res: m[0], end: pos + m[0].length }; }); }
      
      







рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рд▓рд╛рдЧреВ рдХрд░реЗрдВ:



 assert.deepEqual(rgx(/\d+/).exec("123", 0), { res: "123", end: 3 }); assert.deepEqual(rgx(/\d+/).exec("abc", 0), void 0);
      
      







рдлрд┐рд░, рдпрджрд┐ JS рдХреЗ рдкрд╛рд╕ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдирд┐рд░реНрдорд╛рддрд╛ рд╣реИрдВ, рддреЛ rgx (/ abc /) рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдХреЛ / abc / рддрдХ рдЫреЛрдЯрд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред



рд╕рдВрдпреЛрдЬрдХ рдкреИрдЯрд░реНрди





рдЕрдм рдЖрдкрдХреЛ рдХрдИ рдкреИрдЯрд░реНрди рджрд░реНрдЬ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ рдореМрдЬреВрджрд╛ рдкреИрдЯрд░реНрди рдХреЛ рдЬреЛрдбрд╝рддреА рд╣реИред рдЗрдирдореЗрдВ рд╕реЗ рд╕рдмрд╕реЗ рд╕рд░рд▓ "рдХреЙрдореНрдмреАрдиреЗрдЯрд░" рд╡рд┐рдХрд▓реНрдк рд╣реИ - рдпрд╣ рдХрд┐рд╕реА рднреА рдкреИрдЯрд░реНрди рдХреЛ рд╡реИрдХрд▓реНрдкрд┐рдХ рдмрдирд╛рддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рдд рдпрджрд┐ рдореВрд▓ рдкреИрдЯрд░реНрди p рдкрд╛рда рдХреЛ рдкрд╛рд░реНрд╕ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рддреЛ рдЙрд╕реА рдкрд╛рда рдкрд░ рдСрдкреНрдЯ (p) рдХрд╣реЗрдВрдЧреЗ рдХрд┐ рд╕рдм рдХреБрдЫ рдкрд╛рд░реНрд╕ рд╣реЛ рдЧрдпрд╛ рд╣реИ, рдХреЗрд╡рд▓ рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдкрд░рд┐рдгрд╛рдо рд░рд┐рдХреНрдд рд╣реИ:



 function opt(pattern) { return new Pattern(function (str, pos) { return pattern.exec(str, pos) || { res: void 0, end: pos }; }); }
      
      







рдЙрдкрдпреЛрдЧ рдЙрджрд╛рд╣рд░рдг:



 assert.deepEqual(opt(txt("abc")).exec("abc"), { res: "abc", end: 3 }); assert.deepEqual(opt(txt("abc")).exec("123"), { res: void 0, end: 0 });
      
      







рдпрджрд┐ рдСрдкрд░реЗрдЯрд░ рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХрдиреНрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдЬреЗрдПрд╕ рдореЗрдВ рд╕рдВрднрд╡ рдерд╛, рддреЛ рд░рд┐рдХреЙрд░реНрдб рдСрдкреНрдЯ (рдкреА) рдХреЛ рдХрдо рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдкреА || рд╢реВрдиреНрдп 0 (рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рджреЗрдЦрд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рдСрдкреНрдЯ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ)ред



рдЕрдЧрд▓рд╛ рд╕рдмрд╕реЗ рдЬрдЯрд┐рд▓ рдХреЙрдореНрдмреАрдиреЗрдЯрд░ рдПрдХреНрд╕ рд╣реИ - рдпрд╣ рдХреЗрд╡рд▓ рд╡рд╣реА рдмрддрд╛рддрд╛ рд╣реИ рдЬреЛ рдкрд╣рд▓реЗ рдкреИрдЯрд░реНрди рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рджреВрд╕рд░реЗ рдХреЛ рдкрд╛рд░реНрд╕ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ:



 function exc(pattern, except) { return new Pattern(function (str, pos) { return !except.exec(str, pos) && pattern.exec(str, pos); }); }
      
      







рдпрджрд┐ W (p) рдЙрди рдкрд╛рдареЛрдВ рдХрд╛ рд╕рдореВрд╣ рд╣реИ рдЬреЛ p рдкреИрдЯрд░реНрди рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ, рддреЛ W (exc (p, q)) = W (p) \ W (q)ред рдпрд╣ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрдм рдЖрдкрдХреЛ рдкрддреНрд░ рдПрдЪ рдХреЛ рдЫреЛрдбрд╝рдХрд░ рд╕рднреА рдкреВрдВрдЬреА рдкрддреНрд░реЛрдВ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ:



 var p = exc(rgx(/[AZ]/), txt("H")); assert.deepEqual(p.exec("R", 0), { res: "R", end: 1 }); assert.deepEqual(p.exec("H", 0), void 0);
      
      







рдпрджрд┐ JS рдореЗрдВ рдСрдкрд░реЗрдЯрд░ рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ рдерд╛, рддреЛ exc (p1, P2) рдХреЛ p1 - P2 рдпрд╛ to! P2 && p1 рддрдХ рдХрдо рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ (рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕рдХреЗ рд▓рд┐рдП, рд╕рднреА рдХреЛ рдПрдХ рд╕рдВрдпреЛрдЬрди рдкреИрдЯрд░реНрди рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧрд╛ / рдФрд░ рдЬреЛ && рдСрдкрд░реЗрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░реЗрдЧрд╛) ред



рдлрд┐рд░ рдХреЛрдИ рднреА рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рдкреИрдЯрд░реНрди рдЖрддрд╛ рд╣реИ - рдпрд╣ рдХрдИ рдкреИрдЯрд░реНрди рд▓реЗрддрд╛ рд╣реИ рдФрд░ рдПрдХ рдирдпрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЗрди рдкреИрдЯрд░реНрдиреЛрдВ рдореЗрдВ рд╕реЗ рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИред рд╣рдо рдХрд╣ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ W (рдХреЛрдИ рднреА (p1, P2, p3, ...) = W (p1) v W (P2) v W (p3) v ...



 function any(...patterns) { return new Pattern(function (str, pos) { for (var r, i = 0; i < patterns.length; i++) if (r = patterns[i].exec(str, pos)) return r; }); }
      
      







рдореИрдВрдиреЗ ... [(.slice.call (рддрд░реНрдХ, 0)) рдЬреИрд╕реЗ рдЕрдирд╛рдбрд╝реА рдХреЛрдб рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдкреИрдЯрд░реНрди (рд╕рд╛рдордВрдЬрд╕реНрдп: rest_parameters) рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд┐рдпрд╛ред рдХрд┐рд╕реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг:



 var p = any(txt("abc"), txt("def")); assert.deepEqual(p.exec("abc", 0), { res: "abc", end: 3 }); assert.deepEqual(p.exec("def", 0), { res: "def", end: 3 }); assert.deepEqual(p.exec("ABC", 0), void 0);
      
      







рдпрджрд┐ рдЬреЗрдПрд╕ рдореЗрдВ рдСрдкрд░реЗрдЯрд░ рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ рдереЗ, рддреЛ рдХреЛрдИ рднреА (рдкреА 1, рдкреА 2) рдкреА 1 рд╕реЗ рдХрдо рд╣реЛ рд╕рдХрддрд╛ рд╣реИ || p2ред



рдЕрдЧрд▓рд╛ рд╕рдВрдпреЛрдЬрди рдкреИрдЯрд░реНрди seq рд╣реИ - рдпрд╣ рдХреНрд░рдордмрджреНрдз рд░реВрдк рд╕реЗ рдкреИрдЯрд░реНрди рдХреЗ рдЕрдиреБрдХреНрд░рдо рджреНрд╡рд╛рд░рд╛ рдЗрд╕реЗ рджрд┐рдП рдЧрдП рдкрд╛рда рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ:



 function seq(...patterns) { return new Pattern(function (str, pos) { var i, r, end = pos, res = []; for (i = 0; i < patterns.length; i++) { r = patterns[i].exec(str, end); if (!r) return; res.push(r.res); end = r.end; } return { res: res, end: end }; }); }
      
      







рдЗрд╕реЗ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:



 var p = seq(txt("abc"), txt("def")); assert.deepEqual(p.exec("abcdef"), { res: ["abc", "def"], end: 6 }); assert.deepEqual(p.exec("abcde7"), void 0);
      
      







рдпрджрд┐ JS рдореЗрдВ рдСрдкрд░реЗрдЯрд░ рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ рдереЗ, рддреЛ seq (p1, P2) рдХреЛ p1, P2 рддрдХ рдХрдо рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ (рдЕрд▓реНрдкрд╡рд┐рд░рд╛рдо рдСрдкрд░реЗрдЯрд░ рдУрд╡рд░рд▓реЛрдбреЗрдб рд╣реИ)ред



рдФрд░ рдЕрдВрдд рдореЗрдВ, рд░реЗрдк рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рдкреИрдЯрд░реНрди - рдпрд╣ рдХрдИ рдмрд╛рд░ рдкрд╛рда рдХреЗ рд▓рд┐рдП рдкреНрд░рд╕рд┐рджреНрдз рдкреИрдЯрд░реНрди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдкреИрджрд╛ рдХрд░рддрд╛ рд╣реИред рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, рдпрд╣ рдПрдХ рд╣реА рдкреНрд░рдХрд╛рд░ рдХреЗ рдХреБрдЫ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдХрд╣рддреЗ рд╣реИрдВ, рдХреЙрдорд╛рд╕, рдЗрд╕рд▓рд┐рдП рдкреНрд░рддрд┐рдирд┐рдзрд┐ рджреЛ рддрд░реНрдХ рд▓реЗрддреЗ рд╣реИрдВ: рдореБрдЦреНрдп рдкреИрдЯрд░реНрди рдЬрд┐рд╕рдХреЗ рдкрд░рд┐рдгрд╛рдо рд╣рдорд╛рд░реЗ рд▓рд┐рдП рджрд┐рд▓рдЪрд╕реНрдк рд╣реИрдВ рдФрд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреИрдЯрд░реНрди рдЬрд┐рдирдХреЗ рдкрд░рд┐рдгрд╛рдо рддреНрдпрд╛рдЧ рджрд┐рдП рдЧрдП рд╣реИрдВ:



 function rep(pattern, separator) { var separated = !separator ? pattern : seq(separator, pattern).then(r => r[1]); return new Pattern(function (str, pos) { var res = [], end = pos, r = pattern.exec(str, end); while (r && r.end > end) { res.push(r.res); end = r.end; r = separated.exec(str, end); } return { res: res, end: end }; }); }
      
      







рдЖрдк рдПрдХ рдЬреЛрдбрд╝реЗ рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рдкреИрд░рд╛рдореАрдЯрд░ рдорд┐рдирдЯ рдФрд░ рдЕрдзрд┐рдХрддрдо рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░реЗрдЧрд╛ рдХрд┐ рдХрд┐рддрдиреЗ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреА рдЕрдиреБрдорддрд┐ рд╣реИред рдпрд╣рд╛рдБ рдореИрдВрдиреЗ рдлрд╝рдВрдХреНрд╢рди (z) {рд░рд┐рдЯрд░реНрди z [1]} рдирд╣реАрдВ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рддреАрд░ рдлрд╝рдВрдХреНрд╢рди r => r [1] (рд╕рджреНрднрд╛рд╡: arrow_functions) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдкреИрдЯрд░реНрди рдХреЗ рдмрд╛рдж seq рдХреЛ рдХреИрд╕реЗ рдХрдо рдХрд░рддрд╛ рд╣реИ # (рдлрд┐рд░ Promise # рд╕реЗ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рд╡рд┐рдЪрд╛рд░):



 function Pattern(exec) { ... this.then = function (transform) { return new Pattern(function (str, pos) { var r = exec(str, pos); return r && { res: transform(r.res), end: r.end }; }); }; }
      
      







рдпрд╣ рд╡рд┐рдзрд┐ рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рдХреЗ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдордирдорд╛рдирд╛ рдкрд░рд┐рд╡рд░реНрддрди рд▓рд╛рдЧреВ рдХрд░рдХреЗ рджреВрд╕рд░реЗ рдкреИрдЯрд░реНрди рд╕реЗ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред рд╡реИрд╕реЗ, рд╣рд╛рд╕реНрдХреЗрд▓ рдХреЗ рд╡рд┐рд╢реЗрд╖рдЬреНрдЮ, рдХреНрдпрд╛ рдпрд╣ рдХрд╣рдирд╛ рд╕рдВрднрд╡ рд╣реИ рдХрд┐ рдпрд╣ рдкреИрдЯрд░реНрди # рдлрд┐рд░ рдПрдХ рдкреИрдЯрд░реНрди рд╕реЗ рдПрдХ рд╕рдирдХ рдмрдирд╛рддрд╛ рд╣реИ?



рдЦреИрд░, рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:



 var p = rep(rgx(/\d+/), txt(",")); assert.deepEqual(p.exec("1,23,456", 0), { res: ["1", "23", "456"], end: 8 }); assert.deepEqual(p.exec("123ABC", 0), { res: ["123"], end: 3 }); assert.deepEqual(p.exec("ABC", 0), void 0);
      
      







рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╕реНрдкрд╖реНрдЯ рд╕рд╛рджреГрд╢реНрдп рдореЗрд░реЗ рд▓рд┐рдП рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред



рдкрд░рд┐рдгрд╛рдо рдЗрди рд╕рднреА рдкреНрд░рддрд┐рдирд┐рдзрд┐ / seq / рдХрд┐рд╕реА рдХреЗ рд▓рд┐рдП рд▓рдЧрднрдЧ 70 рд▓рд╛рдЗрдиреЗрдВ рд╣реИред рдпрд╣ рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ рдкреИрдЯрд░реНрди рдХреА рд╕реВрдЪреА рдХреЛ рдкреВрд░рд╛ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╣рдо рдПрдХ рдкреИрдЯрд░реНрди рдХреЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдПрдХреНрд╕рдПрдордПрд▓-рдЬреИрд╕реЗ рдкрд╛рда рдХреЛ рдкрд╣рдЪрд╛рдирддрд╛ рд╣реИред



XML- рдЬреИрд╕реЗ рдкрд╛рда рдХреЗ рд▓рд┐рдП рдкрд╛рд░реНрд╕рд░





рд╣рдо рдЦреБрдж рдХреЛ рдРрд╕реЗ XML-рдЬреИрд╕реЗ рдЧреНрд░рдВрдереЛрдВ рддрдХ рд╕реАрдорд┐рдд рд░рдЦрддреЗ рд╣реИрдВ:



 <?xml version="1.0" encoding="utf-8"?> <book title="Book 1"> <chapter title="Chapter 1"> <paragraph>123</paragraph> <paragraph>456</paragraph> </chapter> <chapter title="Chapter 2"> <paragraph>123</paragraph> <paragraph>456</paragraph> <paragraph>789</paragraph> </chapter> <chapter title="Chapter 3"> ... </chapter> </book>
      
      







рдЗрд╕рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдкреИрдЯрд░реНрди рд▓рд┐рдЦреЗрдВрдЧреЗ рдЬреЛ рдлреЙрд░реНрдо рдирд╛рдо рдХреЗ рдПрдХ рдирд╛рдорд┐рдд рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЛ рдкрд╣рдЪрд╛рдирддрд╛ рд╣реИ = "рдореВрд▓реНрдп" - рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдЕрдХреНрд╕рд░ рдПрдХреНрд╕рдПрдордПрд▓ рдореЗрдВ рдкрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:



 var name = rgx(/[az]+/i).then(s => s.toLowerCase()); var char = rgx(/[^"&]/i); var quoted = seq(txt('"'), rep(char), txt('"')).then(r => r[1].join('')); var attr = seq(name, txt('='), quoted).then(r => ({ name: r[0], value: r[2] }));
      
      







рдпрд╣рд╛рдБ attr рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдореВрд▓реНрдп рдХреЗ рд╕рд╛рде рдПрдХ рдирд╛рдорд┐рдд рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЛ рдЙрджреНрдзреГрдд рдХрд░рддрд╛ рд╣реИ, рдЙрджреНрдзреГрдд - рдЙрджреНрдзрд░рдг рдЪрд┐рд╣реНрдиреЛрдВ рдореЗрдВ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ, рдЪрд╛рд░ - рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рдПрдХ рдЕрдХреНрд╖рд░ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ (рдЗрд╕реЗ рдПрдХ рдЕрд▓рдЧ рдкреИрдЯрд░реНрди рдХреЗ рд░реВрдк рдореЗрдВ рдХреНрдпреЛрдВ рд▓рд┐рдЦрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП? рддреЛ, рддреЛ "рд╕рд┐рдЦрд╛рдиреЗ" рдЗрд╕ рдЪрд╛рд░реНрдЯ рддрдерд╛рдХрдерд┐рдд xml рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП? ), рд▓реЗрдХрд┐рди рдирд╛рдо рд╡рд┐рд╢реЗрд╖рддрд╛ рдирд╛рдо рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ (рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрд╣ рдкреВрдВрдЬреА рдФрд░ рдЫреЛрдЯреЗ рдЕрдХреНрд╖рд░реЛрдВ рджреЛрдиреЛрдВ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдкрд╛рд░реНрд╕ рдирд╛рдо рдХреЛ рд╡рд╛рдкрд╕ рд▓реМрдЯрд╛рддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рд╕рднреА рдЕрдХреНрд╖рд░ рдЫреЛрдЯреЗ рд╣реИрдВ)ред рдПрдЯрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:



 assert.deepEqual( attr.exec('title="Chapter 1"', 0), { res: { name: "title", value: "Chapter 1" }, end: 17 });
      
      







рдЕрдЧрд▓рд╛, рд╣рдо рдПрдХ рдРрд╕рд╛ рдкреИрдЯрд░реНрди рдмрдирд╛рддреЗ рд╣реИрдВ рдЬреЛ рд╣реЗрдбрд░ рдХреЛ <<?



 var wsp = rgx(/\s+/); var attrs = rep(attr, wsp).then(r => { var m = {}; r.forEach(a => (m[a.name] = a.value)); return m; }); var header = seq(txt('<?xml'), wsp, attrs, txt('?>')).then(r => r[2]);
      
      







рдпрд╣рд╛рдБ wsp parses рдПрдХ рдпрд╛ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рд░рд┐рдХреНрдд рд╕реНрдерд╛рди, рдПрдХ рдпрд╛ рдЕрдзрд┐рдХ рдирд╛рдорд┐рдд рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдкрд╛рд░реНрд╕ рдХреЛ рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реМрдЯрд╛рддрд╛ рд╣реИ (рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдирд╛рдо-рдорд╛рди рдЬреЛрдбрд╝реЗ рдХреА рдПрдХ рд╕рд░рдгреА рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╢рдмреНрджрдХреЛрд╢ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╕рд░рдгреА рддрдм рд╢рдмреНрджрдХреЛрд╢ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рд╣реЛ рдЬрд╛рддреА рд╣реИ), рдФрд░ рд╢реАрд░реНрд╖ рд▓реЗрдЦ рд╢реАрд░реНрд╖ рд▓реЗрдЦ рдХреЛ рд╕реНрд╡рдпрдВ рдкреНрд░рдХрдЯ рдХрд░рддрд╛ рд╣реИред рдПрдХ рд╣реА рд╢рдмреНрджрдХреЛрд╢ рдХреЗ рд░реВрдк рдореЗрдВ рдХреЗрд╡рд▓ рд╢реАрд░реНрд╖рдХ рдЧреБрдг рджреЗрддрд╛ рд╣реИ:



 assert.deepEqual( header.exec('<?xml version="1.0" encoding="utf-8"?>', 0), { res: { version: "1.0", encoding: "utf-8" }, end: ... });
      
      







рдЕрдм рдЪрд▓рддреЗ рд╣реИрдВ рдлреЙрд░реНрдо рдХреЗ рдиреЛрдбреНрд╕ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВ <рдиреЛрдб ...> ...:



 var text = rep(char).then(r => r.join('')); var subnode = new Pattern((str, pos) => node.exec(str, pos)); var node = seq( txt('<'), name, wsp, attrs, txt('>'), rep(any(text, subnode), opt(wsp)), txt('</'), name, txt('>')) .then(r => ({ name: r[1], attrs: r[3], nodes: r[5] }));
      
      







рдпрд╣рд╛рдБ рдЯреЗрдХреНрд╕реНрдЯ рдиреЛрдб рдХреЗ рдЕрдВрджрд░ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдПрдХ рдЪрд╛рд░ рдкреИрдЯрд░реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ xml рдПрдВрдЯрд┐рдЯреАрдЬ рдХреЛ рдкрд╣рдЪрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рд╕реАрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд╕рдмреНрдиреЛрдб рдЖрдВрддрд░рд┐рдХ рдиреЛрдб (рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рдмреНрдиреЛрдб = рдиреЛрдб) рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдиреЛрдб рдиреЛрдб рдХреЛ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдФрд░ рдЖрдВрддрд░рд┐рдХ рдиреЛрдб рдХреЗ рд╕рд╛рде рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИред рд╕рдмреНрдиреЛрдбреЗ рдХреА рдРрд╕реА рдкреЗрдЪреАрджрд╛ рдкрд░рд┐рднрд╛рд╖рд╛ рдХреНрдпреЛрдВ? рдпрджрд┐ рдЖрдк рдиреЛрдб рдХреЛ рд╕реАрдзреЗ рдиреЛрдб рдХреА рдкрд░рд┐рднрд╛рд╖рд╛ рдореЗрдВ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддреЗ рд╣реИрдВ (рдХреБрдЫ рдЗрд╕ рддрд░рд╣: рдиреЛрдб = seq (..., рдиреЛрдб, ...)), рддреЛ рдпрд╣ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдиреЛрдб рдХреА рдкрд░рд┐рднрд╛рд╖рд╛ рдХреЗ рд╕рдордп рдпрд╣ рдЪрд░ рдЕрднреА рднреА рдЦрд╛рд▓реА рд╣реИред рд╕рдмрдиреЛрдб рдЯреНрд░рд┐рдХ рдЗрд╕ рдкрд░рд┐рдкрддреНрд░ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░рддреА рд╣реИред



рдпрд╣ рдЙрд╕ рдкреИрдЯрд░реНрди рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд░рд╣рддрд╛ рд╣реИ рдЬреЛ рд╣реЗрдбрд░ рдХреЗ рд╕рд╛рде рдкреВрд░реА рдлрд╛рдЗрд▓ рдХреЛ рдкрд╣рдЪрд╛рдирддрд╛ рд╣реИ:



 var xml = seq(header, node).then(r => ({ root: r[1], attrs: r[0] }));
      
      







рдЖрд╡реЗрджрди рддрджрдиреБрд╕рд╛рд░ рд╣реИ:



 assert.deepEqual( xml.exec(src), { attrs: { version: '1.0', encoding: 'utf-8' }, root: { name: 'book', attrs: { title: 'Book 1' }, nodes: [ { name: 'chapter', attrs: { title: 'Chapter 1' }, nodes: [...] }, ... ] } });
      
      







рдпрд╣рд╛рдБ рдореИрдВ рдкреИрдЯрд░реНрди рдХреЛ рдПрдХ рддрд░реНрдХ рдХреЗ рд╕рд╛рде рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдЗрд╕рдХрд╛ рдЕрд░реНрде рдпрд╣ рд╣реИ рдХрд┐ рдореИрдВ рд╢реБрд░реБрдЖрдд рд╕реЗ рд╣реА рддрд╛рд░ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдФрд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реВрдВ рдХрд┐ рдЗрд╕реЗ рдЕрдВрдд рддрдХ рдкрд╛рд░реНрд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЪреВрдВрдХрд┐ рдпрд╣ рдЕрдВрдд рддрдХ рдкрд╛рд░реНрд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдпрд╣ рдХреЗрд╡рд▓ рдЙрд╕ рдЬрдЧрд╣ рдкрд░ рдПрдХ рдкреЙрдЗрдВрдЯрд░ рдХреЗ рдмрд┐рдирд╛ рдкрд╛рд░реНрд╕ рдХрд┐рдП рдЧрдП рдПрдХ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ рдЬрд╣рд╛рдВ рдкрд╛рд░реНрд╕рд░ рдмрдВрдж рд╣реЛ рдЧрдпрд╛ (рдореБрдЭреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдкрдВрдХреНрддрд┐ рдХрд╛ рдЕрдВрдд рд╣реИ):



 function Pattern(name, exec) { ... this.exec = function (str, pos) { var r = exec(str, pos || 0); return pos >= 0 ? r : !r ? null : r.end != str.length ? null : r.res; }; }
      
      







рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдкреВрд░рд╛ рдкрд╛рд░реНрд╕рд░ 20 рд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ рд╣реИ (рдЙрди 70 рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдордд рднреВрд▓реЛ рдЬреЛ рдкреНрд░рддрд┐рдирд┐рдзрд┐, seq, рдХрд┐рд╕реА рднреА, рдЖрджрд┐ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ):



 var name = rgx(/[az]+/i).then(s => s.toLowerCase()); var char = rgx(/[^"&]/i); var quoted = seq(txt('"'), rep(char), txt('"')).then(r => r[1].join('')); var attr = seq(name, txt('='), quoted).then(r => ({ name: r[0], value: r[2] })); var wsp = rgx(/\s+/); var attrs = rep(attr, wsp).then(r => { var m = {}; r.forEach(a => (m[a.name] = a.value)); return m; }); var header = seq(txt('<?xml'), wsp, attrs, txt('?>')).then(r => r[2]); var text = rep(char).then(r => r.join('')); var subnode = new Pattern((str, pos) => node.exec(str, pos)); var node = seq( txt('<'), name, wsp, attrs, txt('>'), rep(any(text, subnode), opt(wsp)), txt('</'), name, txt('>')) .then(r => ({ name: r[1], attrs: r[3], nodes: r[5] })); var xml = seq(header, node).then(r => ({ root: r[1], attrs: r[0] }));
      
      







JS (рдпрд╛ C ++) рдореЗрдВ рдСрдкрд░реЗрдЯрд░ рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ рдХреЗ рд╕рд╛рде, рдпрд╣ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛:



 var name = rgx(/[az]+/i).then(s => s.toLowerCase()); var char = rgx(/[^"&]/i); var quoted = ('"' + rep(char) + '"').then(r => r[1].join('')); var attr = (name + '=' + quoted).then(r => ({ name: r[0], value: r[2] })); var wsp = rgx(/\s+/); var attrs = rep(attr, wsp).then(r => { var m = {}; r.forEach(a => (m[a.name] = a.value)); return m; }); var header = ('<?xml' + wsp + attrs + '?>').then(r => r[2]); var text = rep(char).then(r => r.join('')); var subnode = new Pattern((str, pos) => node.exec(str, pos)); var node = ('<' + name + wsp + attrs + '>' + rep(text | subnode) + (wsp | null) + '</' + name + '>') .then(r => ({ name: r[1], attrs: r[3], nodes: r[5] })); var xml = (header + node).then(r => ({ root: r[1], attrs: r[0] }));
      
      







рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рдпрд╣рд╛рдВ рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрд╕реНрдХрд░рдг рд╕рдЦреНрддреА рд╕реЗ рдПрдХ рдПрдмреАрдПрдирдПрдл рдирд┐рдпрдо рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рдЖрдкрдХреЛ рдЖрд░рдПрдлрд╕реА рдореЗрдВ рд╡рд░реНрдгрди рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдХреБрдЫ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдФрд░ рд╡рд╣рд╛рдВ рдЙрдиреНрд╣реЗрдВ рдПрдмреАрдПрдирдПрдл рдкрд╕рдВрдж рд╣реИ), рддреЛ рдЙрди рдирд┐рдпрдореЛрдВ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рдПрдХ рдпрд╛рдВрддреНрд░рд┐рдХ рдорд╛рдорд▓рд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЪреВрдВрдХрд┐ рдПрдмреАрдПрдирдПрдл рдирд┐рдпрдо рдЦреБрдж (рд╕рд╛рде рд╣реА рдИрдмреАрдПрдирдПрдл рдФрд░ рдкреАрдИрдЬреА) рд╕рдЦреНрддреА рд╕реЗ рдФрдкрдЪрд╛рд░рд┐рдХ рд╣реИрдВ, рдЖрдк рдЗрди рдирд┐рдпрдореЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд╛рд░реНрд╕рд░ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдлрд┐рд░, рдкреНрд░рддрд┐рдирд┐рдзрд┐, рд╕реАрдХ, рдЖрджрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХреБрдЫ рд▓рд┐рдЦреЗрдВ:



 var dataurl = new ABNF('"data:" mime ";" attrs, "," data', { mime: /[az]+\/[az]+/i, attrs: ..., data: /.*/ }).then(r => ({ mime: r[1], attrs: r[3], data: r[5] }));
      
      







рдФрд░ рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣ рд▓рд╛рдЧреВ рдХрд░реЗрдВ:



 assert.deepEqual( dataurl.exec('data:text/plain;charset="utf-8",how+are+you%3f'), { mime: "text/plain", attrs: { charset: "utf-8" }, data: "how are you?" });
      
      







рдХреБрдЫ рдФрд░ рдмреАрдЪреЗ





рдпрджрд┐ рдкрд╛рд░реНрд╕ рд╡рд┐рдлрд▓ рд╣реБрдЖ рддреЛ рдкреИрдЯрд░реНрди # рдирд┐рд╖реНрдкрд╛рджрди рд░рд┐рдЯрд░реНрди рдЕрд╢рдХреНрдд / рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рдХреНрдпреЛрдВ рд╣реИ? рдЕрдкрд╡рд╛рдж рдХреНрдпреЛрдВ рдирд╣реАрдВ рдлреЗрдВрдХрддреЗ? рдпрджрд┐ рдЖрдк рдЗрд╕ рддрд░рд╣ рд╕реЗ рдЕрдкрд╡рд╛рджреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдкрд╛рд░реНрд╕рд░ рд╣рд░ рдмреАрд╕ рдзреАрдорд╛ рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рдЕрдкрд╡рд╛рдж рдЕрд╕рд╛рдзрд╛рд░рдг рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫреЗ рд╣реИрдВред



рд╡рд░реНрдгрд┐рдд рд╡рд┐рдзрд┐ рдЖрдкрдХреЛ рдПрд▓рдПрд▓ рдкрд╛рд░реНрд╕рд░ рд▓рд┐рдЦрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИ рдЬреЛ рд╕рднреА рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рдирд╣реАрдВ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЖрдкрдХреЛ рдлрд╝реЙрд░реНрдо рдХреЗ XML рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ



 <book attr1="..." attr2="..."    ???
      
      







рдЙрд╕ рдЬрдЧрд╣ рдкрд░ рдЬрд╣рд╛рдВ рдпрд╣ рдЦрдбрд╝рд╛ рд╣реИ ??? рдпрд╣ рджреЛрдиреЛрдВ / рдФрд░ рдмрд╕> рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЕрдм рдЕрдЧрд░ LL рдкрд╛рд░реНрд╕рд░ рдиреЗ рдпрд╣ рд╕рдм <рдХрд┐рддрд╛рдм ...> рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд▓реЗрдХрд┐рди рдЬрдЧрд╣ рдореЗрдВ ??? рдпрд╣ рдирд┐рдХрд▓рд╛ >>, рддреЛ рдкрд╛рд░реНрд╕рд░ рд╕рдм рдХреБрдЫ рддреНрдпрд╛рдЧ рджреЗрдЧрд╛ рдХрд┐ рдпрд╣ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдореЗрдВ рдЗрддрдирд╛ рд▓рдВрдмрд╛ рд╕рдордп рд▓рдЧрд╛ рдФрд░ рдЗрд╕ рдзрд╛рд░рдгрд╛ рдХреЗ рддрд╣рдд рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ <рдХрд┐рддрд╛рдм рд╣реИ ... />ред рдПрд▓рдЖрд░ рдкрд╛рд░реНрд╕рд░ рдЗрд╕ рдЦрд╛рдореА рд╕реЗ рдореБрдХреНрдд рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЙрдиреНрд╣реЗрдВ рд▓рд┐рдЦрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИред



рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдПрд▓рдПрд▓ рдкрд╛рд░реНрд╕рд░ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рд╡рд╛рдХреНрдп-рд╡рд┐рдиреНрдпрд╛рд╕ / рдЧрдгрд┐рддреАрдп рднрд╛рд╡реЛрдВ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЦрд░рд╛рдм рд░реВрдк рд╕реЗ рдЕрдиреБрдХреВрд▓ рд╣реИрдВ, рдЬрд╣рд╛рдВ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рд╛рдердорд┐рдХрддрд╛рдУрдВ рд╡рд╛рд▓реЗ рдСрдкрд░реЗрдЯрд░ рд╣реИрдВ, рдЖрджрд┐ред рдПрд▓рдПрд▓ рдкрд╛рд░реНрд╕рд░ рдмреЗрд╢рдХ рдЖрдк рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдХреБрдЫ рднреНрд░рдорд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рд╣реЛрдЧрд╛ рдФрд░ рдзреАрд░реЗ-рдзреАрд░реЗ рдХрд╛рдо рдХрд░реЗрдЧрд╛ред LR рдкрд╛рд░реНрд╕рд░ рдЕрдкрдиреЗ рдЖрдк рднреНрд░рдорд┐рдд рд╣реЛ рдЬрд╛рдПрдЧрд╛, рд▓реЗрдХрд┐рди рддреЗрдЬ рд╣реЛрдЧрд╛ред рдЗрд╕рд▓рд┐рдП, рдЗрд╕ рддрд░рд╣ рдХреЗ рднрд╛рд╡ рддрдерд╛рдХрдерд┐рдд рддрдерд╛рдХрдерд┐рдд рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИрдВ рдкреНрд░реИрдЯ рдХрд╛ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдЬреЛ рдХреНрд░реЙрдХрдлреЛрд░реНрдб рдиреЗ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╕рдордЭрд╛рдпрд╛ (рдпрджрд┐ рдпрд╣ рд▓рд┐рдВрдХ рдмреИрдВрдЧрдиреА рд╣реИ, рддреЛ рдЖрдк рд╢рд╛рдпрдж рдкрд╛рд░реНрд╕рд░ рдХреЛ рдореБрдЭрд╕реЗ рдмреЗрд╣рддрд░ рд╕рдордЭрддреЗ рд╣реИрдВ рдФрд░ рдЖрдк рд╢рд╛рдпрдж рдпрд╣ рд╕рдм рдкрдврд╝рдХрд░ рдмрд╣реБрдд рдКрдм рдЧрдП рд╣реИрдВ)ред



рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдХреЛрдИ рдХрд╛рдо рдЖрдПрдЧрд╛ред рдПрдХ рд╕рдордп рдореЗрдВ, рдореИрдВрдиреЗ рдЕрдирд╛рдбрд╝реА рдбрд┐рдЧреНрд░реА рдХреЗ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЕрдВрд╢реЛрдВ рдХреЗ рдкрд╛рд░реНрд╕рд░ рд▓рд┐рдЦреЗ рдереЗ, рдФрд░ рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рд╡рд┐рдзрд┐ рдореЗрд░реЗ рд▓рд┐рдП рдПрдХ рдЦреЛрдЬ рдереАред



All Articles