UNPKG

closingbracket

Version:

Find in a string a closing bracket for an opening bracket. The search function will start from a specific start index in the string, identifies the start index of the next corresponding opening bracket and finds the corresponding closing bracket provided

393 lines (369 loc) 13.9 kB
/* --------------------------------------- Exported Module Variable: BracketHandler Package: closingbracket Version: 1.0.9 Date: 2020/10/20 8:37:05 Homepage: https://github.com/niebert/closingbracket#readme Author: Engelbert Niehaus License: MIT Date: 2020/10/20 8:37:05 Require Module with: const BracketHandler = require('closingbracket'); JSHint: installation with 'npm install jshint -g' ------------------------------------------ */ /*jshint laxcomma: true, asi: true, maxerr: 150 */ /*global alert, confirm, console, prompt */ /* --------------------------------------- Exported Module Variable: BracketHandler Package: closingbracket Version: 1.0.4 Date: 2020/10/16 19:04:09 Homepage: https://github.com/niebert/closingbracket#readme Author: Engelbert Niehaus License: MIT Date: 2020/10/16 19:04:09 Require Module with: const BracketHandler = require('closingbracket'); JSHint: installation with 'npm install jshint -g' ------------------------------------------ */ /*jshint laxcomma: true, asi: true, maxerr: 150 */ /*global alert, confirm, console, prompt */ function find_closing_bracket(expression,closebracket,startsearch_at){ var openbracket = "-"; var vResult = { "start_search": (startsearch_at || 0), "openbracket_at": -1, "closebracket_at": -1 }; switch (closebracket) { case "]": openbracket = "["; break; case "}": openbracket = "{"; break; case ")": openbracket = "("; break; case ">": openbracket = "<"; break; default: // undefined bracket openbracket = "-"; } if (openbracket != "-") { var index = startsearch_at; // check character at index if it is already // the opening bracket. while ((index < expression.length) && (expression.charAt(index)!=openbracket)) { index++; } if (index < expression.length) { vResult.openbracket_at = index; //console.log("Opening Bracket '" + openbracket+ "' found at position "+index); var bracket_stack = []; // Traverse through string starting from // given index. while (index < expression.length){ if (expression.charAt(index) == openbracket) { // If current character is an // opening bracket push it in stack. // that is performed for the first bracket as well. bracket_stack.push(expression.charAt(index)); } else { // If current character is a closing // bracket, remove one opening bracket // from the bracket stack - i.e. pop from stack. // If bracket stack is empty, then this closing // bracket is the corresponding bracket for the // first bracket pushed. if (expression.charAt(index) == closebracket) { bracket_stack.pop(); if (bracket_stack.length == 0) { //console.log("Closing Bracket '" + closebracket+ "' found at position "+index); vResult.closebracket_at = index; index = expression.length; } } } index++; } } else { console.error("Opening Bracket not found in expression"); } } return vResult; } /* var str = "MyCheck(asdas(iasd)asdas asd) ashdj(sakdjk))"; console.log("String: '" + str + "'"); var vResult = find_closing_bracket(str,")",2); console.log("Result: "+JSON.stringify(vResult,null,4)); console.log("Open Char At " + vResult.openbracket_at + ": '" + str.charAt(vResult.openbracket_at) + "'"); console.log("Close Char At " + vResult.closebracket_at + ": '" + str.charAt(vResult.closebracket_at) + "'"); */ function find_command_name(expression,startsearch_at) { var index = (startsearch_at || 0); var cmd_name = "-"; // undefined; var vReturn = find_closing_bracket(expression,"}",1); /* undefined results for var vResult = { "start_search": 0, "openbracket_at": -1, "closebracket_at": -1 }; */ //console.log("expression 3='"+expression+"'"); if (vReturn.openbracket_at >= 0) { if (vReturn.closebracket_at >= 0) { cmd_name = expression.substring(vReturn.openbracket_at+1,vReturn.closebracket_at); console.log("newcommand found var='" + cmd_name + "'"); } } if (cmd_name == "-") { console.error("CALL: find_command_name() - command name not found"); } return cmd_name; } function replaceStringReverse(pString,pReplace,pSearch) //###### replaces in the string "pString" multiple substrings "pSearch" by "pReplace" { return replaceString(pString,pSearch,pReplace); } function replaceString(pString,pSearch,pReplace) //###### replaces in the string "pString" multiple substrings "pSearch" by "pReplace" { //console.log("string.js - replaceString() "+typeof(pString)); var vString = pString || ""; var vSearch = pSearch || ""; var vReturnString = ''; if (typeof(pString) != "string") { pString = ""; } else if (vSearch == "") { console.log("replaceString(pString,pSearch,pReplace) pSearch undefined"); } else if (vString != '') { pString = vString; var vHelpString = ''; var vN = vString.indexOf(pSearch); while (vN >= 0) { if (vN > 0) vReturnString += pString.substring(0, vN); vReturnString += pReplace; if (vN + pSearch.length < pString.length) { pString = pString.substring(vN+pSearch.length, pString.length); } else { pString = '' }; vN = pString.indexOf(pSearch); }; }; return vReturnString + pString; }; function parse_newcommands(expression,index) { var vNewCommands = []; index = index || 0; expression = expression.substr(index); while (expression.indexOf("\\newcommand{")>=0) { var cmd = { "name": "", "definition":"undefined latex newcommand", "params":0 }; //console.log("expression 1='"+expression+"'"); index = expression.indexOf("\\newcommand{"); expression = expression.substr(index); //console.log("expression 3='"+expression+"'"); var cmd_name = find_command_name(expression,0); if (cmd_name != "-") { cmd.name = cmd_name; // 12 = length "\newcommand{" // cmd_name.length = 6 for cmd_name="\mycmd" // \newcommand{\mycmd}[3] var m = 12 + cmd_name.length + 3; if (expression.indexOf("[") <= m) { var vReturn = find_closing_bracket(expression,"]",12 + cmd_name.length); /* undefined results for var vResult = { "start_search": 0, "openbracket_at": -1, "closebracket_at": -1 }; */ var param_count = 0; if (vReturn.openbracket_at >= 0) { if (vReturn.closebracket_at >= 0) { param_count = parseInt(expression.substring(vReturn.openbracket_at+1,vReturn.closebracket_at)); console.log("Command '" + cmd.name + "' has " + param_count + " parameter"); } } //console.log("Command: '" + cmd_name + "' has "+ param_count+" parameters"); cmd.params = param_count; expression = expression.substr(expression.indexOf("}")+1); //console.log("expression before definition parsing='"+expression+"'"); vReturn = find_closing_bracket(expression,"}",0); if (vReturn.openbracket_at >= 0) { if (vReturn.closebracket_at >= 0) { cmd.definition = expression.substring(vReturn.openbracket_at+1,vReturn.closebracket_at); //console.log("Definition found for newcommand='" + cmd_name + "' with definition\n'" + cmd.definition + "'"); expression = expression.substr(cmd.definition.length + expression.indexOf("]") + 3); //console.log("expression after definition found='"+expression+"'"); } } } vNewCommands.push(cmd); } else { console.error("Command Name not found!"); break; } } return vNewCommands; } function extract_parameter(expression,count,index) { var vResult = { "params":[], "end_at": 0 }; // push all parameters to the array e.g. // \mycmd{first}{second par}{third} // vParam = ["first","second par","third"] var p=0; while (p < count) { vReturn = find_closing_bracket(expression,"}",index); if (vReturn.openbracket_at >= 0) { if (vReturn.closebracket_at >= 0) { var param = expression.substring(vReturn.openbracket_at+1,vReturn.closebracket_at); vResult.params.push(param); index = vReturn.closebracket_at + 1; console.log("Parameter "+(p+1)+" found '" + param + "'"); } // set the end of the parameter as end vResult.end_at = index; } else { console.error("Parameter "+(p+1)+" could not be parsed!"); } p++; } return vResult; } function replace_cmd_definition(cmd,params) { // \mycmd{FIRST}{SECOND} // vParam = ["FIRST","SECOND"] /* cmd = { "name": "\mycmd", "definition":"defined text #1 with two #2 parameters in latex definition", "params":2 }; def4replace="defined text FIRST with two SECOND parameters in latex definition" */ var def4replace = cmd.definition; for (var i = 0; i < params.length; i++) { def4replace = replaceString(def4replace,"#"+(i+1),params[i]); } return def4replace; } function expand_newcommand(expression,cmd,found) { var index = found; // \mycmd{asdasd}{asdasd}{asdas} /* cmd = { "name": "\mycmd", "definition":"defined text #1 with two #2 parameters in latex definition", "params":2 }; */ console.log("Command '" + cmd.name + "' has "+cmd.params+" parameter."); if (cmd.params == 0) { console.log("[0] Command '" + cmd.name + "' has "+cmd.params+" parameter."); expression = replaceString(expression,cmd.name,cmd.definition); } else { console.log("[" + cmd.params + "] Command '" + cmd.name + "' has "+cmd.params+" parameter."); var vResult = extract_parameter(expression,cmd.params,found); var def4replace = replace_cmd_definition(cmd,vResult.params); var search = expression.substring(found,vResult.end_at); expression = replaceString(expression,search,def4replace); } return expression; } function replace_count_newcommands(expression,pNewCommands) { var count = 0; for (var i = 0; i < pNewCommands.length; i++) { var cmd = pNewCommands[i]; //console.log("replace_count_newcommands('" + cmd.name + "')"); var search = cmd.name + "{"; var vFound = expression.indexOf(search); while (vFound >= 0) { count++; expression = expand_newcommand(expression,cmd,vFound); // check if the expression contains more uses of the command cmd vFound = expression.indexOf(search); } } console.log("CALL: replace_count_newcommands() - replacements count="+count); return { "expression":expression, "count":count }; } function replace_newcommands(expression,pNewCommands,pmax_recursion) { var max_recursion = pmax_recursion || 5; // macros may also contain other LaTeX commands. // so replacement of the macro in first recursion // needs further replacements of the replaced macros in // the newcommand definition. var recursions = 0; // recursions count the number of recursions the are already performed // max_recursion defines the number of maximal recursions // that will be performed by the newcommand replacements, // the parameter can be set by the function parameters. // if not set the default recursion depth is 5. // max_recursion is safety mechanism for the function. // so that it terminates even if there is a cycle newcommand replacment. // e.g. command "cmd1" uses "cmd2" in the definition and // "cmd2" uses "cmd1" in its definition. if (pNewCommands) { while (recursions < max_recursion) { recursions++; console.log("replace_newcommands() recursion [" +recursions + "]"); var vResult = replace_count_newcommands(expression,pNewCommands); if (vResult.count == 0) { recursions = max_recursion } else { expression = vResult.expression; } } } else { console.error("ERROR: pNewCommands not defined for replacing commands"); } return expression; } var latex = "Beispiel: \n \\newcommand{\\mycmd}[3]{Gleichung (\\ref{#1}) $\\frac{#2}{#3}$ Ende} bewirkt\n bei Einsatz in \\mycmd{Nr1}{Bla}{Blub} die Ausgabe"; latex += "\\newcommand{\\secondcmd}[4]{Gleichung {hjsd{}{}} enge} askjdkasld \\noparamdef ladslkl"; latex += "\n \\newcommand{\\noparamdef}{Definition as a no parameter {New{C}{om}}mand } askjdkasld"; latex = "Beispiel: \\newcommand{\\mycmd}[3]{Gleichung (\\ref{#1}) $\\frac{#2}{#3}$ Ende} bewirkt\n bei Einsatz in \\mycmd{Nr1}{Bla}{Blub} die Ausgabe \\mycmd{FIRST}{SECOND}{THIRD} XXXX"; latex = ` \\newcommand{\\tool}[2]{Title #1: The #1 is used for #2} \\newcommand{\\cmd}[3]{\\int_{#1}^{#2} f(#3) d#3} \\tool{hammer}{nails} \\tool{hammer}{nails} \\tool{hammer}{nails} Mathematical expressions are $\\cmd{4}{5}{x}$ and $\\cmd{a}{b}{y}$ `; latex = ` \\newcommand{\\tool}[2]{\\tooltitle{#1} The #1 is used for #2} \\newcommand{\\tooltitle}[1]{Title #1: } \\tool{hammer}{nails} `; var vNewCommands = parse_newcommands(latex); console.log("JSON: "+ JSON.stringify(vNewCommands,null,4)); var expression = replace_newcommands(latex,vNewCommands); console.log("-------------------------------------"); console.log("Source: '" + latex + "'"); console.log("-------------------------------------"); console.log("Result: '" + expression + "'"); console.log("-------------------------------------"); var BracketHandler = { "find_closing_bracket": find_closing_bracket, "parse_newcommands": parse_newcommands, "replace_newcommands": replace_newcommands };