Advertisement
mvaganov

stringbonus.cs

Nov 26th, 2016
274
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // MIT license - Michael Vaganov, 2016
  2. (function(globals) {
  3. ///////////////////////////////////////////////////////////////////////////////
  4.  
  5. //add functionality to the String implementation...
  6. (function () {
  7.   "use strict";
  8.   if (typeof String.prototype.startsWith !== 'function') {
  9.     String.prototype.startsWith = function (str) {
  10.       return this.substring(0, str.length) === str; //this.slice(0, str.length) === str;
  11.     }
  12.   }
  13.   if (typeof String.prototype.replaceAll !== 'function') {
  14.     /**
  15.      * @param {string} str1
  16.      * @param {string} str2
  17.      * @param {(boolean|null)} ignore ignore case?
  18.      * @return {string} a new string, a copy of this one, with all instances of str1 replaced with str2.
  19.      */
  20.     String.prototype.replaceAll = function(str1, str2, ignore) {
  21.       return this.replace(new RegExp(
  22.         str1.replace(
  23.           /([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, "\\$&"
  24.         ),
  25.         (ignore?"gi":"g")),
  26.         (typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2
  27.       );
  28.     }
  29.   }
  30.   if (typeof String.prototype.indexOfOneOfThese !== 'function') {
  31.     /**
  32.      * @param {Array<String>} listOfDelimeters possible string delimeters that are being sought after
  33.      * @param {number=} start where to start looking in the string
  34.      * @return {Array<number>} [index that has one of these first, which delimeter was actually found here].
  35.      * if none of these exist, returns [this.length, -1]
  36.      * return[0] is the index
  37.      * return[1] is the index of the delimeter that was found
  38.      */
  39.     String.prototype.indexOfOneOfThese = function (listOfDelimeters, start) {
  40.       var bestIndex = this.length;
  41.       var foundDelimeter = -1;
  42.       if(start == null || start == undefined) start = 0;
  43.       for(var i = 0; i < listOfDelimeters.length; ++i) {
  44.         var index = this.indexOf(listOfDelimeters[i], start);
  45.         if(index >= 0 && index < bestIndex) {
  46.           foundDelimeter  = i;
  47.           bestIndex = index;
  48.         }
  49.       }
  50.       return [bestIndex, foundDelimeter];
  51.     }
  52.   }
  53.   if (typeof String.prototype.hasAt !== 'function') {
  54.     String.prototype.hasAt = function (token, index) {
  55.       if(token.length+index > this.length) { return false; }
  56.       for(var i=0;i<token.length;++i) {
  57.         if(token[i] !== this[i+index]) {
  58.           return false;
  59.         }
  60.       }
  61.       return true;
  62.     }
  63.   }
  64.   if (typeof String.prototype.isAt !== 'function') {
  65.     String.prototype.isAt = String.prototype.hasAt;
  66.   }
  67.   if (typeof String.prototype.trimTokens !== 'function') {
  68.     String.prototype.trimTokens = function (tokens) {
  69.       var start = 0, end = this.length;
  70.       var foundOne = false;
  71.       // from front
  72.       do{
  73.         foundOne = false;
  74.         for(var i=0;i<tokens.length;++i) {
  75.           if(this.hasAt(tokens[i], start)) {
  76.             //console.log("@BEG "+this);
  77.             //this.splice(0,tokens[i].length);
  78.             //i=0;
  79.             start += tokens[i].length;
  80.             foundOne = true;
  81.           }
  82.         }
  83.       }while(foundOne);
  84.       // from back
  85.       do{
  86.         foundOne = false;
  87.         for(var i=0;i<tokens.length;++i) {
  88.           if(this.hasAt(tokens[i], end-tokens[i].length)) {
  89.             // console.log("@END "+this);
  90.             // this.splice(index,tokens[i].length);
  91.             // i=0;
  92.             end -= tokens[i].length;
  93.             foundOne = true;
  94.           }
  95.         }
  96.       }while(foundOne);
  97.       return this.substring(start,end);
  98.     }
  99.   }
  100.   if (typeof String.prototype.splitByOneOfThese !== 'function') {
  101.     /**
  102.      * @param {Array<String>} listOfDelimeters possible string delimeters that are being sought after
  103.      * @param {Number} maxSplits how many times to split. will split from left to right. -1 means no limit
  104.      * @return {Array<String>} as split, except with multiple delimeter tokens
  105.      */
  106.     String.prototype.splitByOneOfThese = function (listOfDelimeters, maxSplits, listOfDelimetersToInclude, respectStringLiterals) {
  107.       if(maxSplits == null) maxSplits = -1;
  108.       var splitted = [], index = 0, whereToSplit, segment, splitCount = 0;
  109.       for(var i = 0; index < this.length; ++i) {
  110.         if(maxSplits >= 0 && splitCount >= maxSplits) {
  111.           whereToSplit = [this.length, -1];
  112.         } else {
  113.           var cursor = index;
  114.           var doneLooking;
  115.           do {
  116.             var literalStart = null;
  117.             var literalEnd = null;
  118.             if(respectStringLiterals) {
  119.               var literalDelims = ["\"","\'"];
  120.               literalStart = this.indexOfOneOfThese(literalDelims, cursor);
  121.               if(literalStart[1] != -1) {
  122.                 // console.log("0found "+literalDelims[literalStart[1]]+" at "+literalStart[0]+".");
  123.                 var cursor = literalStart[0];
  124.                 do {
  125.                   cursor += 1;
  126.                   literalEnd = this.indexOfOneOfThese([literalDelims[literalStart[1]]], cursor);
  127.                   // console.log("ending "+[literalDelims[literalStart[1]]]+" at "+literalEnd[0]+"?");
  128.                   if(this[literalEnd[0]-1] == '\\'){
  129.                     cursor = literalEnd[0]+1;
  130.                   }
  131.                 } while(literalEnd[1] >= 0 && this[literalEnd[0]-1] == '\\');
  132.                 // console.log("1found ending "+[literalDelims[literalStart[1]]]+" at "+literalEnd[0]+". ("+this[literalEnd[0]-1]+")");
  133.               }
  134.               // else { console.log("no literals found past "+cursor); }
  135.             }
  136.             cursor = index; // start over, before the string literal was found.
  137.             doneLooking = true;
  138.             whereToSplit = this.indexOfOneOfThese(listOfDelimeters, cursor);
  139.             // console.log("2found \'"+listOfDelimeters[whereToSplit[1]]+"\' at "+whereToSplit[0]+".");
  140.             // if(literalStart && literalEnd) console.log("????"+whereToSplit[1]+" != -1 && "+whereToSplit[0]+" > "+literalStart[0]+" && "+whereToSplit[0]+" < "+literalEnd[0]);
  141.             if(literalStart && literalEnd && whereToSplit[1] != -1 && whereToSplit[0] > literalStart[0] && whereToSplit[0] < literalEnd[0]) {
  142.               // console.log("---the break is in the literal. keep looking, past the literal!");
  143.               cursor = literalEnd[0]+1;
  144.               index = cursor;
  145.               doneLooking = false;
  146.               segment = this.substring(literalStart[0], literalEnd[0]+1);
  147.               // console.log("adding string literal "+segment);
  148.               splitCount++;
  149.               if(segment.length > 0) {
  150.                 splitted.push(segment);
  151.               }
  152.             }
  153.           } while(!doneLooking);
  154.         }
  155.         segment = this.slice(index, whereToSplit[0]);
  156.         //console.log("("+index+", "+whereToSplit[0]+"... "+whereToSplit[1]+") ="+segment);
  157.         splitCount++;
  158.         if(segment.length > 0) {
  159.           splitted.push(segment);
  160.         }
  161.         index = whereToSplit[0];
  162.         var whichDelimeterWasSplitOn = listOfDelimeters[whereToSplit[1]];
  163.         if(whichDelimeterWasSplitOn && listOfDelimetersToInclude && listOfDelimetersToInclude.indexOf(whichDelimeterWasSplitOn) >= 0) {
  164.           splitted.push(whichDelimeterWasSplitOn);
  165.         }
  166.         if(whereToSplit[1] != -1) {
  167.           index += listOfDelimeters[whereToSplit[1]].length;
  168.         }
  169.       }
  170.       return splitted;
  171.     }
  172.   }
  173.   if (typeof String.prototype.splitIntoTable !== 'function') {
  174.     /**
  175.      * @param {Array<String>} listOfEntryDelimeters example: {@code ["{", "}", ","]}
  176.      * @param {Array<String>} listOfAssignmentDelimeters example: {@code ["=",":"]}
  177.      * @return {Object<String,String>} a key/value pair table. see {@link String#prototype#parseCookies} as an example
  178.      */
  179.     String.prototype.splitIntoTable = function (listOfEntryDelimeters, listOfAssignmentDelimeters) {
  180.       // first, split by entry delimeters
  181.       var entries = this.splitByOneOfThese(listOfEntryDelimeters);
  182.       // then split in half by the assignment delimeter
  183.       var table = {};
  184.       for(var i = 0; i < entries.length; ++i) {
  185.         var pair = entries[i].splitByOneOfThese(listOfAssignmentDelimeters, 1);
  186.         var name = pair[0].trim();
  187.         var value = (pair.length > 1)?pair[1].trim():undefined;
  188.         if (!table[name] || value && value.length > 0) {
  189.           table[name] = value;
  190.         }
  191.       }
  192.       return table;
  193.     }
  194.   }
  195. })();
  196. /**
  197.  * @return {Map<String,String>} a table of cookies parameters, assuming this is formatted like an html cookie.
  198.  */
  199. function parseCookies(str) { return str.splitIntoTable([";"], ["=", ":"]); }
  200.  
  201. /**
  202. * @param text {String} text to parse
  203. * @param out_htmlTags {?Array<Object>} where to put HTML tags discovered in the parsing. each tag will have a 'tagName'
  204. * @return text without HTML in it
  205. */
  206. function separateTextAndHtml(text, out_htmlTags) {
  207.   function stripOutHtmlTags(text) {
  208.     var resultText = "";
  209.     var cursor = 0;
  210.     do {
  211.       var index = text.indexOf("<", cursor);
  212.       if(index >= 0) {
  213.         resultText += text.substring(cursor, index);
  214.         var endIndex = text.indexOf(">", index+1);
  215.         if(endIndex >= 0) {
  216.           cursor = endIndex+1;
  217.           if(out_htmlTags) {
  218.             var subtext = text.substring(index, endIndex);
  219.             var tokens = subtext.splitByOneOfThese([" ","=","<",">","\n","\t","\r"], -1, ["="], true);
  220.             var tag = {};
  221.             if(tokens.length >= 1) {
  222.               tag.tagName = tokens[0];
  223.             }
  224.             for(var i=1;i<tokens.length;++i){
  225.               if(tokens[i+1] == "=") {
  226.                 var val = tokens[i+2];
  227.                 if((val[0] == '\"' && val[val.length-1] == '\"') || (val[0] == '\'' && val[val.length-1] == '\'')) {
  228.                   val = val.substring(1, val.length-1);
  229.                 }
  230.                 tag[tokens[i]] = val;
  231.                 i+=2;
  232.               } else {
  233.                 tag[tokens[i]] = undefined;
  234.               }
  235.             }
  236.             out_htmlTags.push(tag);
  237.             if(tag.tagName == "br" || tag.tagName == "hr") {
  238.               resultText += "\n";
  239.             }
  240.           }
  241.         } else {
  242.           cursor = text.length;
  243.         }
  244.       } else {
  245.         resultText += text.substring(cursor, text.length);
  246.         cursor = text.length;
  247.       }
  248.     } while(cursor < text.length);
  249.     return resultText;
  250.   }
  251.   var str = stripOutHtmlTags(text);
  252.   var trimmed = str.trimTokens([" ","\n","\r","\t"])
  253.   // console.log(str+" --trim-> "+trimmed);
  254.   return trimmed;
  255. }
  256.  
  257. ///////////////////////////////////////////////////////////////////////////////
  258.   if (typeof define !== 'undefined' && define.amd) { define([], function () { return parseCookies; }); // RequireJS
  259.   } else if (typeof module !== 'undefined' && module.exports) {
  260.     module.exports.parseCookies = parseCookies; // CommonJS
  261.     module.exports.separateTextAndHtml = separateTextAndHtml; // CommonJS
  262.   } else { globals.parseCookies = parseCookies; // <script>
  263.     globals.separateTextAndHtml = separateTextAndHtml;
  264.   }
  265. })(this);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement