"use strict"; /** * @fileOverview These methods test a string for various attributes * in a string * @module ink/strings/types * @author Terry Weiss * @author zumbrunn * @author Esa-Matti Suurone * @requires ink/strings/shape * @requires ink/strings/patterns * @requires lodash */ var shape = require( "./shape" ); var sys = require( "lodash" ); var patterns = require( "./patterns" ); /** * checks if a date format pattern is correct * * @param {String} * string the string to check * @returns {Boolean} true if the pattern is correct * @example * var strings = require("ink-strings"); * strings.isDateFormat("waka waka") * -> false * * strings.isDateFormat("01/01/2013") * -> true */ exports.isDateFormat = function ( string ) { var test = Date.parse( string ); var res = false; if ( !isNaN( test ) ) { res = true; } return res; }; /** * function checks if the string passed contains any characters that are forbidden in URLs and tries to create a * java.net.URL from it * * @param {String} * string the string to check * @returns {Boolean} * @example * var strings = require("ink-strings"); * strings.isUrl("waka waka") * -> false * * strings.isUrl("http://home.com/terry") * -> true * * strings.isUrl("ftp://home.com/terry") * -> true * * strings.isUrl("file://home.com/terry") * -> false // this is arguably wrong, but this is what you should expect from this method */ exports.isUrl = function ( string ) { return patterns.URLPATTERN.test( string ); }; /** * function checks a string for a valid color value in hexadecimal format. it may also contain # as first character * * @param {String} * string the string to check * @returns {Boolean} false, if string length (without #) > 6 or < 6 or contains any character which is not a valid hex * value * @example * var strings = require("ink-strings"); * strings.isHexColor("fred is a great guy"); * -> false * * strings.isHexColor("#FF0000"); * -> true * * strings.isHexColor("ABCDEF"); * -> true * * strings.isHexColor("ABCDEF00"); * -> false */ exports.isHexColor = function ( string ) { if ( string.indexOf( "#" ) === 0 ) { string = string.substring( 1 ); } return string.length === 6 && !patterns.HEXPATTERN.test( string ); }; /** * function returns true if the string contains only a-z and 0-9 (case insensitive!) * * @returns Boolean true in case string is alpha, false otherwise */ exports.isAlphanumeric = function ( string ) { return string.length && !patterns.ANUMPATTERN.test( string ); }; /** * function returns true if the string contains only characters a-z * * @returns Boolean true in case string is alpha, false otherwise */ exports.isAlpha = function ( string ) { return string.length && !patterns.APATTERN.test( string ); }; /** * function returns true if the string contains only 0-9 * * @returns Boolean true in case string is numeric, false otherwise */ exports.isNumeric = function ( string ) { return string.length && !patterns.NUMPATTERN.test( string ); }; /** * Returns true if string starts with the given substring * * @param {String} * string the string to search in * @param {String} * substring pattern to search for * @returns {Boolean} true in case it matches the beginning of the string, false otherwise */ exports.startsWith = function ( string, substring ) { return string.indexOf( substring ) === 0; }; /** * Returns true if string ends with the given substring * * @param {String} * string the string to search in * @param {String} * substring pattern to search for * @returns Boolean true in case it matches the end of the string, false otherwise */ exports.endsWith = function ( string, substring ) { var diff = string.length - substring.length; return diff > -1 && string.lastIndexOf( substring ) === diff; }; /** * Returns true if string contains substring. * * @param {String} * string the string to search in * @param {String} * substring the string to search for * @param {Number=} * fromIndex optional index to start searching * @returns true if str is contained in this string * @type Boolean */ exports.contains = function ( string, substring, fromIndex ) { fromIndex = fromIndex || 0; return string.indexOf( substring, fromIndex ) > -1; }; /** * returns true if the string looks like an e-mail * * @param {String} * string */ exports.isEmail = function ( string ) { return patterns.EMAILPATTERN.test( string ); }; /** * Get the longest common segment that two strings have in common, starting at the beginning of the string * * @param {String} * str1 a string * @param {String} * str2 another string * @returns {String} the longest common segment * @example * strings.getCommonPrefix("Chocolate Fudge", "Choco Mocha") * -> "Choco" * * strings.getCommonPrefix("Chocolate Fudge", "cocoa") * -> "" */ exports.getCommonPrefix = function ( str1, str2 ) { if ( sys.isNull( str1 ) || sys.isNull( str2 ) ) { return null; } else if ( str1.length > str2.length && str1.indexOf( str2 ) === 0 ) { return str2; } else if ( str2.length > str1.length && str2.indexOf( str1 ) === 0 ) { return str1; } var length = Math.min( str1.length, str2.length ); for ( var i = 0; i < length; i++ ) { if ( str1[ i ] !== str2[ i ] ) { return str1.slice( 0, i ); } } return str1.slice( 0, length ); }; /** * Counts the instances of one string inside another * * @param {string} * str The string to look in * @param {string} * substr The pattern to count * @returns {Number} */ exports.count = function ( str, substr ) { if ( sys.isNull( str ) || sys.isNull( substr ) ) { return 0; } return String( str ).split( substr ).length - 1; }; /** * Searches a string from left to right for a pattern and returns a substring consisting of the characters in the string * that are to the right of the pattern or all string if no match found. * * @param {string} * str * @param {string}sep * The pattern to look for * @returns {string} */ exports.strRight = function ( str, sep ) { if ( sys.isNull( str ) ) { return ''; } str = String( str ); sep = !sys.isNull( sep ) ? String( sep ) : sep; var pos = !sep ? -1 : str.indexOf( sep ); //noinspection JSHint return ~pos ? str.slice( pos + sep.length, str.length ) : str; }; /** * Searches a string from right to left for a pattern and returns a substring consisting of the characters in the string * that are to the right of the pattern or all string if no match found. * * @param {string} * str * @param {string}sep * The pattern to look for * @returns {string} */ exports.strRightBack = function ( str, sep ) { if ( sys.isNull( str ) ) { return ''; } str = String( str ); sep = !sys.isNull( sep ) ? String( sep ) : sep; var pos = !sep ? -1 : str.lastIndexOf( sep ); //noinspection JSHint return ~pos ? str.slice( pos + sep.length, str.length ) : str; }; /** * Searches a string from left to right for a pattern and returns a substring consisting of the characters in the string * that are to the left of the pattern or all string if no match found. * * @param {string} * str * @param {string}sep * The pattern to look for * @returns {string} */ exports.strLeft = function ( str, sep ) { if ( sys.isNull( str ) ) { return ''; } str = String( str ); sep = !sys.isNull( sep ) ? String( sep ) : sep; var pos = !sep ? -1 : str.indexOf( sep ); //noinspection JSHint return ~pos ? str.slice( 0, pos ) : str; }; /** * Searches a string from right to left for a pattern and returns a substring consisting of the characters in the string * that are to the left of the pattern or all string if no match found. * * @param {string} * str * @param {string}sep * The pattern to look for * @returns {string} */ exports.strLeftBack = function ( str, sep ) { if ( sys.isNull( str ) ) { return ''; } str += ''; sep = !sys.isNull( sep ) ? '' + sep : sep; var pos = str.lastIndexOf( sep ); //noinspection JSHint return ~pos ? str.slice( 0, pos ) : str; }; /** * Calculates Levenshtein distance between two strings. * * @see http://en.wikipedia.org/wiki/Levenshtein_distance * @param {string} * str1 The first string to look at * @param {string} * str2 The second string to look at * @returns {number} */ exports.levenshtein = function ( str1, str2 ) { if ( str1 === null && str2 === null ) { return 0; } if ( str1 === null ) { return String( str2 ).length; } if ( str2 === null ) { return String( str1 ).length; } str1 = String( str1 ); str2 = String( str2 ); var prev = null; var current = [], value; for ( var i = 0; i <= str2.length; i++ ) { for ( var j = 0; j <= str1.length; j++ ) { if ( i && j ) { if ( str1.charAt( j - 1 ) === str2.charAt( i - 1 ) ) { value = prev; } else { value = Math.min( current[ j ], current[ j - 1 ], prev ) + 1; } } else { value = i + j; } prev = current[ j ]; current[ j ] = value; } } return current.pop(); };