Greasy Fork is available in English.

Str Lib

String helper functions

Script này sẽ không được không được cài đặt trực tiếp. Nó là một thư viện cho các script khác để bao gồm các chỉ thị meta // @require https://greasyfork.org/scripts/27278-str-lib/code/Str%20Lib.js?version=175156

(function (global, Str) {
    "use strict";

    // region [ Private Functions ]
    /**
     * Test if the specified object is an array.
     * @param obj {Array|object}
     * @returns {boolean}
     * @private
     */
    function _isArray(obj) {
        return Object.prototype.toString.call(obj) === '[object Array]';
    }

    /**
     * Convert json string into js object.
     * @param s
     * @private
     */
    function _parseJson(s) {
        var _parser;
        if (typeof global.JSON !== 'undefined') {
            _parser = global.JSON.parse;
        }
        else if (typeof window.jQuery !== 'undefined') {
            _parser = window.jQuery.parseJSON;
        }

        if (typeof _parser === 'undefined') {
            throw 'Undefined JSON method';
        }
        return _parser(s);
    }

    // endregion

    /**
     * Check for undefined, null, zero length, blanks or s is false.
     * @param s {string|object} - string, array or object to test.
     * @returns {boolean}
     * Unit Test: http://jsfiddle.net/wao20/TGP3N/
     */
    Str.empty = function (s) {
        // s == undefined	 <= double equals is deliberate, check for null and undefined
        return !!(s == undefined
        || s.length === 0
        || Str.trim(s).length === 0
        || !s);

    };

    /**
     * Compare two strings
     * @param s1 {?string}
     * @param s2 {?string}
     * @param caseSensitive {boolean=}
     * @returns {boolean}
     */
    Str.equals = function (s1, s2, caseSensitive) {
        if (s1 == undefined || s2 == undefined) {
            return false;
        }

        if (caseSensitive) {
            return s1 == s2;
        }
        return s1.toLowerCase() == s2.toLowerCase();
    };

    /**
     * empty(), '0', '0.0', 'false' => false. Otherwise return !!s.
     *
     * @param s {?string}
     * @returns {boolean}
     */
    Str.boolVal = function (s) {
        if (Str.empty(s)) {
            return false;
        }
        s = Str.trim(s).toLowerCase();
        if (s == '0' || s == '0.0' || s == 'false') {
            return false;
        }
        return !!s;
    };

    /**
     * Escape the string to be use as a literal in regex expression.
     *
     * @param s {string|Array}
     * @returns {string|Array}
     */
    Str.regexEscape = function (s) {
        if (!s) {
            return '';
        }

        if (typeof s === 'string') {
            return s.replace(/([.?*+\^$\[\]\\(){}|\-])/g, '\\$1');
        }
        else if (_isArray(s)) {
            var result = [], i;
            for (i = 0; i < s.length; i++) {
                result.push(Str.regexEscape(s[i]));
            }
            return result;
        }
        return s;
    };

    /**
     * Tests whether the beginning of a string matches pattern.
     *
     * @param s {string}
     * @param pattern {string} - to find
     * @param caseSensitive {boolean=}
     * @return {boolean}
     */
    Str.startsWith = function (s, pattern, caseSensitive) {
        if (caseSensitive) {
            return s.indexOf(pattern) === 0;
        }
        return s.toLowerCase().indexOf(pattern.toLowerCase()) === 0;
    };

    /**
     * Test if string ends with specified pattern
     * @param s {string}
     * @param pattern {string}
     * @param caseSensitive {boolean=}
     * @returns {boolean}
     */
    Str.endsWith = function (s, pattern, caseSensitive) {
        var d = s.length - pattern.length;
        if (caseSensitive) {
            return d >= 0 && s.lastIndexOf(pattern) === d;
        }
        return d >= 0 && s.toLowerCase().lastIndexOf(pattern.toLowerCase()) === d;
    };

    /**
     * Check if the string contains a substring.
     * @param s {string}
     * @param needle {string}
     * @param caseSensitive {boolean=}
     * @return {boolean}
     */
    Str.contains = function (s, needle, caseSensitive) {
        if (Str.empty(s) || Str.empty(needle)) {
            return false;
        }
        if (caseSensitive) {
            return s.indexOf(needle) > -1;
        }
        return s.toLowerCase().indexOf(needle.toLowerCase()) > -1;
    };

    /**
     * Must contains all the element in the array.
     * @param s {string}
     * @param needles {Array|string}
     * @param caseSensitive {boolean=}
     * @return {boolean}
     */
    Str.containsAll = function (s, needles, caseSensitive) {
        var i = 0;
        if (_isArray(needles)) {
            for (i = 0; i < needles.length; i++) {
                if (!Str.contains(s, needles[i], caseSensitive)) {
                    return false;
                }
            }
            return true;
        }
        return Str.contains(s, needles, caseSensitive);
    };

    /**
     * Must contains ANY the element in the array.
     * @param s {string}
     * @param needles {Array|string}
     * @param caseSensitive {boolean=}
     * @return {boolean}
     */
    Str.containsAny = function (s, needles, caseSensitive) {
        var i;
        if (_isArray(needles)) {
            for (i = 0; i < needles.length; i++) {
                if (Str.contains(s, needles[i], caseSensitive)) {
                    return true;
                }
            }
            return false;
        }
        return Str.contains(s, needles, caseSensitive);
    };

    /**
     * Determine if the specified variable is a string
     * @param o
     * @returns {boolean}
     */
    Str.isString = function (o) {
        return typeof o === 'string';
    };

    /**
     * Trims white space from the beginning and end of a string.
     * @param s {string}
     * @param c {string=}
     * @return {string}
     */
    Str.trim = function (s, c) {
        if (!Str.isString(s)) {
            return s;
        }

        if (c == undefined || c == ' ') {
            if (String.prototype.trim) {
                return String.prototype.trim.call(s);
            }
            return s.replace(/^\s+/, '').replace(/\s+$/, '');
        }
        return Str.trimStart(Str.trimEnd(s, c), c);
    };

    /**
     * Remove chars/Str from the start of the string
     * @param s
     * @param c {string|Array=} - supports Str.trimStart(s, ['0x0', '0', 'x']);
     */
    Str.trimStart = function (s, c) {
        if (c == undefined || c == '') {
            return s.replace(/^\s+/, '');
        }

        var trims = c, regex, result;
        if (!_isArray(c)) {
            trims = [c];
        }
        trims = Str.regexEscape(trims).join('|');
        regex = '^(' + trims + '|\s)+';
        regex = new RegExp(regex, 'g');
        result = s.replace(regex, '');
        return result;
    };

    /**
     * Remove chars/Str(s) from the end of the string
     * @param s {string}
     * @param c {string|Array=} - supports Str.trimEnd(s, ['0x0', '0', 'x']);
     */
    Str.trimEnd = function (s, c) {
        if (c == undefined) {
            return s.replace(/\s+$/, '');
        }
        var trims = c, regex, result;
        if (!_isArray(c)) {
            trims = [c];
        }
        trims = Str.regexEscape(trims).join('|');
        regex = '(' + trims + '|\s)+$';
        regex = new RegExp(regex, 'g');
        result = s.replace(regex, '');
        return result;
    };

    /**
     * Extended substring, support negative index (ordinal js substr(startIndex, endIndex))
     *
     * @param s {string}
     * @param index {number} - if negative take string from the right similar to php substr()
     * @param len {number=} - number of char to take starting from the index to the right (even when index is negative)
     * @return {string}
     */
    Str.subStr = function (s, index, len) {
        if (s == undefined) {
            return '';
        }

        len = len || 0;

        if (Math.abs(index) > s.length) {
            return s;
        }

        // regular substring
        if (index > -1) {
            if (len > 0 && (index + len) < s.length) {
                return s.substring(index, index + len);
            }
            return s.substring(index);
        }

        // Negative index, take string from the right
        // Index is negative	=> subStr ('hello', -3)	=> 'llo'
        var start = s.length + index;
        if (len > 0 && (start + len) < s.length) {
            return s.substring(start, start + len);
        }
        return s.substring(start);
    };

    /**
     * Count number of occurrences of an substring.
     * @param s {string} - the big string
     * @param sub {string} - the little string you want to find.
     * @param caseSensitive {boolean=}
     * @returns {number}
     */
    Str.subCount = function (s, sub, caseSensitive) {
        sub = Str.regexEscape(sub);

        if (caseSensitive) {
            return s.split(sub).length - 1;
        }
        return s.toLowerCase().split(sub.toLowerCase()).length - 1;
    };

    /**
     * Concatenate count number of copies of s together and return result.
     * @param s {string}
     * @param count {number} - Number of times to repeat s
     * @return {string}
     */
    Str.repeat = function (s, count) {
        var result = '', i;
        for (i = 0; i < count; i++) {
            result += s;
        }
        return result;
    };

    /**
     * Pad left
     *
     * @param s {!string}
     * @param padStr {!string} - the padding
     * @param totalLength {!number} - the final length after padding
     * @return {string}
     */
    Str.padLeft = function (s, padStr, totalLength) {
        return s.length >= totalLength ? s : Str.repeat(padStr, (totalLength - s.length) / padStr.length) + s;
    };

    /**
     * Pad right
     *
     * @param s {string}
     * @param padStr {string} - the padding
     * @param totalLength {number} - the final length after padding
     * @return {string}
     */
    Str.padRight = function (s, padStr, totalLength) {
        return s.length >= totalLength ? s : s + Str.repeat(padStr, (totalLength - s.length) / padStr.length);
    };

    /**
     * Pad string based on the boolean value.
     *
     * @param s {string}
     * @param padStr {string} - the padding
     * @param totalLength {number} - the final length after padding
     * @param padRight {boolean} - pad right if true, pad left otherwise
     * @return {string}
     */
    Str.pad = function (s, padStr, totalLength, padRight) {
        if (padRight) {
            return Str.padRight(s, padStr, totalLength);
        }
        return Str.padLeft(s, padStr, totalLength);
    };

    /**
     * Strips any HTML tags from the specified string.
     * @param s {string}
     * @return {string}
     */
    Str.stripTags = function (s) {
        return s.replace(/<\/?[^>]+>/gi, '');
    };

    /**
     * escapeHTML from Prototype-1.6.0.2 -- If it's good enough for Webkit and IE, it's good enough for Gecko!
     * Converts HTML special characters to their entity equivalents.
     *
     * @param s {string}
     * @return {string}
     */
    Str.escapeHTML = function (s) {
        s = s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
        return s;
    };

    /**
     * unescapeHTML from Prototype-1.6.0.2 -- If it's good enough for Webkit and IE, it's good enough for Gecko!
     * Strips tags and converts the entity forms of special HTML characters to their normal form.
     *
     * @param s {string}
     * @return {string}
     */
    Str.unescapeHTML = function (s) {
        return Str.stripTags(s).replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
    };

    /**
     * Remove all Viet's accents and replace it with the latin based alphabet
     * @param s {string}
     * @return {string}
     */
    Str.stripViet = function (s) {
        /*
         data = data.replace(/[àáâãăạảấầẩẫậắằẳẵặ]/g, 'a');
         data = data.replace(/[òóôõơọỏốồổỗộớờởỡợ]/g, 'o');
         data = data.replace(/[èéêẹẻẽếềểễệ]/g, 'e');
         data = data.replace(/[ùúũưụủứừửữự]/g, 'u');
         data = data.replace(/[ìíĩỉị]/g, 'i');
         data = data.replace(/[ýỳỵỷỹ]/g, 'y');
         data = data.replace(/[đðĐ]/g, 'd');
         */

        if (Str.empty(s)) {
            return s;
        }

        s = s.replace(/[\u00E0\u00E1\u00E2\u00E3\u0103\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7]/g, 'a');
        s = s.replace(/[\u00F2\u00F3\u00F4\u00F5\u01A1\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3]/g, 'o');
        s = s.replace(/[\u00E8\u00E9\u00EA\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7]/g, 'e');
        s = s.replace(/[\u00F9\u00FA\u0169\u01B0\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1]/g, 'u');
        s = s.replace(/[\u00EC\u00ED\u0129\u1EC9\u1ECB]/g, 'i');
        s = s.replace(/[\u00FD\u1EF3\u1EF5\u1EF7\u1EF9]/g, 'y');
        s = s.replace(/[\u0111\u00F0\u0110]/g, 'd');

        return s;
    };

    /**
     * Use this to constructs multi lines string
     *
     * eg. Str.multiLines(true,
     *                        'hello',
     *                        'world'
     *                        );
     *                    returns: "hello\nworld"
     *
     * @param glue {string} - the separator between each line (eg. '\n', ', ' or ' ')
     * @param args {...string} - each line
     */
    Str.multiLines = function (glue, args) {
        args = Array.prototype.splice.call(arguments, 1);
        return args.join(glue);
    };

    /**
     * Try to parse the json, if valid return the object else return defaultValue
     *
     * @param s {string} - json string
     * @param defaultValue {boolean|object=} - if not specified defaultValue=false
     * @returns {boolean|object}
     */
    Str.parseJson = function (s, defaultValue) {
        defaultValue = defaultValue === undefined ? false : defaultValue;
        if (Str.empty(s)) {
            return defaultValue;
        }

        try {
            if (typeof s === 'string') {
                return _parseJson(s);
            }

            // it already an object
            return s;
        }
        catch (err) {
            return defaultValue;
        }
    };

    /**
     * Escape the attribute, make sure it doesn't break the attribute select or to be use a an attribute.
     * @param s {string} - the string
     */
    Str.escapeAttribute = function (s) {
        return s.replace(/"/g, '\\"');
    };

    /**
     * Reverse the string.
     *
     * @param s
     * @returns {*}
     */
    Str.reverse = function (s) {
        if (s) {
            return s.split('').reverse().join('');
        }
        return s;
    };

    /**
     * Get all the matched based on the specified group.
     *
     * @param s {string}
     * @param regex {RegExp}
     * @param index {Number} - the index of the match.
     * @returns {Array}
     */
    Str.matchAll = function (s, regex, index) {
        var m, result = [];
        index = index || 0;

        if (!s) {
            return [];
        }

        while (m = regex.exec(s)) {
            result.push(m[index]);
        }
        return result;
    };

    /**
     * Split the string into multiple smaller chunks.
     *
     * @param s
     * @param chunkSize
     * @returns {Array}
     */
    Str.chop = function (s, chunkSize) {
        var regex;
        if (!s) {
            return [];
        }
        regex = new RegExp('.{1,' + chunkSize + '}', 'g');
        return s.match(regex);
    };

    function _getWords(s) {
        s = s.replace(/(\w)([A-Z][a-z])/, '$1-$2');
        s = s.replace(' ', '-');
        s = s.replace('_', '-');
        s = s.replace(/-+/g, '-');

        return s.split('-')
    }

    /**
     * Convert any string to camel case.
     *
     * @param s
     */
    Str.toCamelCase = function (s) {
        var words = _getWords(s), result = '', i, word;
        for (i = 0; i < words.length; i++) {
            word = words[i];
            if (i == 0) {
                result += word.toLowerCase();
            }
            else {
                result += word.charAt(0).toUpperCase() + word.substr(1).toLowerCase();
            }
        }
        return result;
    };

    /**
     * Convert any string to title case.
     *
     * @param s
     */
    Str.toTitleCase = function (s) {
        var words = _getWords(s), result = '', i, word;
        for (i = 0; i < words.length; i++) {
            word = words[i];
            result += word.charAt(0).toUpperCase() + word.substr(1).toLowerCase() + ' ';
        }
        return Str.trimEnd(result);
    };

    /**
     * Convert any string to snake case.
     *
     * @param s
     */
    Str.toSnakeCase = function (s) {
        var words = _getWords(s), result = '', i, word;
        for (i = 0; i < words.length; i++) {
            word = words[i];
            result += word.toLowerCase() + '_';
        }
        return Str.trimEnd(result, '_');
    };

    /**
     * Convert any string to-kebab-case.
     *
     * @param s
     */
    Str.toKebabCase = function (s) {
        var words = _getWords(s), result = '', i, word;
        for (i = 0; i < words.length; i++) {
            word = words[i];
            result += word.toLowerCase() + '-';
        }
        return Str.trimEnd(result, '-');
    };

}(window, window._Str = {}));