diff --git a/persian.js b/persian.js index 75a3130..d2419a0 100755 --- a/persian.js +++ b/persian.js @@ -1,4 +1,4 @@ -/** +/** * PersianJs v0.4.0 * https://github.com/usablica/persian.js * MIT licensed @@ -6,368 +6,519 @@ * Copyright (C) 2012 usabli.ca and other contributors */ (function () { - - // Default config/variables - var VERSION = "0.4.0", - // Check for nodeJS - hasModule = (typeof module !== 'undefined' && module.exports); - - // Declare Number Arrays in different locales - var arabicNumbers = ["١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩", "٠"], - persianNumbers = ["۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹", "۰"], - englishNumbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]; - - /** - * PersianJs main class - * - * @class PersianJs - */ - function PersianJs(str) { - this._str = str; + // Default config/variables + var VERSION = "0.4.0", + // Check for nodeJS + hasModule = typeof module !== "undefined" && module.exports; + + // Declare Number Arrays in different locales + var arabicNumbers = ["١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩", "٠"], + persianNumbers = ["۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹", "۰"], + englishNumbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]; + + /** + * PersianJs main class + * + * @class PersianJs + */ + function PersianJs(str) { + this._str = str; + } + + /** + * Used for convert Arabic characters to Persian + * + * @api private + * @method _arabicChar + * @param {String} value + * @return {Object} PersianJs Object + */ + function _arabicChar(value) { + if (!value) { + return ""; } - /** - * Used for convert Arabic characters to Persian - * - * @api private - * @method _arabicChar - * @param {String} value - * @return {Object} PersianJs Object - */ - function _arabicChar(value) { - if (!value) { - return; - } - var arabicChars = ["ي", "ك", "‍", "دِ", "بِ", "زِ", "ذِ", "ِشِ", "ِسِ", "ى","ة"], - persianChars = ["ی", "ک", "", "د", "ب", "ز", "ذ", "ش", "س", "ی","ه"]; - - for (var i = 0, charsLen = arabicChars.length; i < charsLen; i++) { - value = value.replace(new RegExp(arabicChars[i], "g"), persianChars[i]); - } - this._str = value; - return this; + const arabicChars = [ + "ي", + "ك", + "‍", + "دِ", + "بِ", + "زِ", + "ذِ", + "ِشِ", + "ِسِ", + "ى", + "ة", + ]; + const persianChars = ["ی", "ک", "", "د", "ب", "ز", "ذ", "ش", "س", "ی", "ه"]; + + return arabicChars.reduce( + (acc, char, index) => + acc.replace(new RegExp(char, "g"), persianChars[index]), + value + ); + } + + /** + * Used for convert Persian numbers to English + * + * @api private + * @method _persianNumber + * @param {String} value + * @return {Object} PersianJs Object + */ + function _persianNumber(value) { + if (!value) { + return ""; } - /** - * Used for convert Persian numbers to English - * - * @api private - * @method _persianNumber - * @param {String} value - * @return {Object} PersianJs Object - */ - function _persianNumber(value) { - if (!value) { - return; - } - - for (var i = 0, numbersLen = englishNumbers.length; i < numbersLen; i++) { - value = value.replace(new RegExp(persianNumbers[i], "g"), englishNumbers[i]); - } - - this._str = value; - return this; + const persianNumbers = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"]; + const englishNumbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]; + + return persianNumbers.reduce( + (acc, number, index) => + acc.replace(new RegExp(number, "g"), englishNumbers[index]), + value + ); + } + + /** + * Used for convert Arabic numbers to Persian + * + * @api private + * @method _arabicNumber + * @param {String} value + * @return {Object} PersianJs Object + */ + function _arabicNumber(value) { + if (!value) { + return ""; } - /** - * Used for convert Arabic numbers to Persian - * - * @api private - * @method _arabicNumber - * @param {String} value - * @return {Object} PersianJs Object - */ - function _arabicNumber(value) { - if (!value) { - return; - } - value=value.toString(); - - for (var i = 0, numbersLen = arabicNumbers.length; i < numbersLen; i++) { - value = value.replace(new RegExp(arabicNumbers[i], "g"), persianNumbers[i]); - } - this._str = value; - return this; + value = value.toString(); + const arabicNumbers = ["٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"]; + const persianNumbers = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"]; + + return arabicNumbers.reduce( + (acc, number, index) => + acc.replace(new RegExp(number, "g"), persianNumbers[index]), + value + ); + } + + /** + * Used for convert English numbers to Persian + * + * @api private + * @method _englishNumber + * @param {String} value + * @return {Object} PersianJs Object + */ + function _englishNumber(value) { + if (!value) { + return; } - - /** - * Used for convert English numbers to Persian - * - * @api private - * @method _englishNumber - * @param {String} value - * @return {Object} PersianJs Object - */ - function _englishNumber(value) { - if (!value) { - return; - } - value=value.toString(); - var englishNumbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], - persianNumbers = ["۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹", "۰"]; - - for (var i = 0, numbersLen = englishNumbers.length; i < numbersLen; i++) { - value = value.replace(new RegExp(englishNumbers[i], "g"), persianNumbers[i]); - } - this._str = value; - return this; + value = value.toString(); + var englishNumbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], + persianNumbers = ["۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹", "۰"]; + + for (var i = 0, numbersLen = englishNumbers.length; i < numbersLen; i++) { + value = value.replace( + new RegExp(englishNumbers[i], "g"), + persianNumbers[i] + ); } - - /** - * Used for convert Persian and Arabic numbers to English string - * - * @api private - * @method _toEnglishNumber - * @param {String} value - * @return {Object} PersianJs Object - */ - function _toEnglishNumber(value) { - if (!value) { - return; - } - for (var i = 0, numbersLen = englishNumbers.length; i < numbersLen; i++) { - value = value.replace(new RegExp(persianNumbers[i], "g"), englishNumbers[i]) - .replace(new RegExp(arabicNumbers[i], "g"), englishNumbers[i]); - } - this._str = value; - return this; + this._str = value; + return this; + } + + /** + * Used for convert Persian and Arabic numbers to English string + * + * @api private + * @method _toEnglishNumber + * @param {String} value + * @return {Object} PersianJs Object + */ + function _toEnglishNumber(value) { + if (!value) { + return ""; } - /** - * Used for decode Persian Charachters in URL - * https://fa.wikipedia.org/wiki/مدیاویکی:Gadget-Extra-Editbuttons-Functions.js - * - * @api private - * @method _decodeURL - * @param {String} value - * @return {Object} PersianJs Object - */ - function _decodeURL(value) { - if (!value) { - return; - } - // Replace every %20 with _ to protect them from decodeURI - var old = ""; - while (old != value) { - old = value; - value = value.replace(/(http\S+?)\%20/g, '$1\u200c\u200c\u200c_\u200c\u200c\u200c'); - } - // Decode URIs - // NOTE: This would convert all %20's to _'s which could break some links - // but we will undo that later on - value = value.replace(/(http\S+)/g, function (s, p) { - return decodeURI(p); - }); - // Revive all instances of %20 to make sure no links is broken - value = value.replace(/\u200c\u200c\u200c_\u200c\u200c\u200c/g, '%20'); - this._str = value; - return this; + value = value.toString(); + const englishNumbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]; + const persianNumbers = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"]; + + return englishNumbers.reduce( + (acc, number, index) => + acc.replace(new RegExp(number, "g"), persianNumbers[index]), + value + ); + } + + /** + * Used for decode Persian Charachters in URL + * https://fa.wikipedia.org/wiki/مدیاویکی:Gadget-Extra-Editbuttons-Functions.js + * + * @api private + * @method _decodeURL + * @param {String} value + * @return {Object} PersianJs Object + */ + function _decodeURL(value) { + if (!value) { + return; + } + // Replace every %20 with _ to protect them from decodeURI + var old = ""; + while (old != value) { + old = value; + value = value.replace( + /(http\S+?)\%20/g, + "$1\u200c\u200c\u200c_\u200c\u200c\u200c" + ); + } + // Decode URIs + // NOTE: This would convert all %20's to _'s which could break some links + // but we will undo that later on + value = value.replace(/(http\S+)/g, function (s, p) { + return decodeURI(p); + }); + // Revive all instances of %20 to make sure no links is broken + value = value.replace(/\u200c\u200c\u200c_\u200c\u200c\u200c/g, "%20"); + this._str = value; + return this; + } + + /** + * Used for Change keyboard layout + * + * @api private + * @method _switchKey + * @param {String} value + * @return {Object} PersianJs Object + */ + function _switchKey(value) { + if (!value) { + return; + } + var persianChar = [ + "ض", + "ص", + "ث", + "ق", + "ف", + "غ", + "ع", + "ه", + "خ", + "ح", + "ج", + "چ", + "ش", + "س", + "ی", + "ب", + "ل", + "ا", + "ت", + "ن", + "م", + "ک", + "گ", + "ظ", + "ط", + "ز", + "ر", + "ذ", + "د", + "پ", + "و", + "؟", + "ئ", + ], + englishChar = [ + "q", + "w", + "e", + "r", + "t", + "y", + "u", + "i", + "o", + "p", + "[", + "]", + "a", + "s", + "d", + "f", + "g", + "h", + "j", + "k", + "l", + ";", + "'", + "z", + "x", + "c", + "v", + "b", + "n", + "m", + ",", + "?", + "m", + ]; + + for (var i = 0, charsLen = persianChar.length; i < charsLen; i++) { + value = value.replace(new RegExp(persianChar[i], "g"), englishChar[i]); + } + this._str = value; + return this; + } + + /** + * Used for get persian words representation of a number + * + * @api private + * @method _digitsToWords + * @param {String} value + * @return {Object} PersianJs Object + */ + function _digitsToWords(value) { + var delimiter, digit, i, iThree, numbers, parts, result, resultThree, three; + + if (!isFinite(value)) { + return ""; } - /** - * Used for Change keyboard layout - * - * @api private - * @method _switchKey - * @param {String} value - * @return {Object} PersianJs Object - */ - function _switchKey(value) { - if (!value) { - return; - } - var persianChar = [ "ض", "ص", "ث", "ق", "ف", "غ", "ع", "ه", "خ", "ح", "ج", "چ", "ش", "س", "ی", "ب", "ل", "ا", "ت", "ن", "م", "ک", "گ", "ظ", "ط", "ز", "ر", "ذ", "د", "پ", "و","؟","ئ" ], - englishChar = [ "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "z", "x", "c", "v", "b", "n", "m", ",","?","m" ]; - - for (var i = 0, charsLen = persianChar.length; i < charsLen; i++) { - value = value.replace(new RegExp(persianChar[i], "g"), englishChar[i]); - } - this._str = value; - return this; + if (typeof value !== "string") { + value = value.toString(); } - /** - * Used for get persian words representation of a number - * - * @api private - * @method _digitsToWords - * @param {String} value - * @return {Object} PersianJs Object - */ - function _digitsToWords(value) { - var delimiter, digit, i, iThree, numbers, parts, result, resultThree, three; - - if (!isFinite(value)) { - return ''; - } - - if (typeof value !== "string") { - value = value.toString(); - } - - parts = ['', 'هزار', 'میلیون', 'میلیارد', 'تریلیون', 'کوادریلیون', 'کویینتیلیون', 'سکستیلیون']; - numbers = { - 0: ['', 'صد', 'دویست', 'سیصد', 'چهارصد', 'پانصد', 'ششصد', 'هفتصد', 'هشتصد', 'نهصد'], - 1: ['', 'ده', 'بیست', 'سی', 'چهل', 'پنجاه', 'شصت', 'هفتاد', 'هشتاد', 'نود'], - 2: ['', 'یک', 'دو', 'سه', 'چهار', 'پنج', 'شش', 'هفت', 'هشت', 'نه'], - two: ['ده', 'یازده', 'دوازده', 'سیزده', 'چهارده', 'پانزده', 'شانزده', 'هفده', 'هجده', 'نوزده'], - zero: 'صفر' - }; - delimiter = ' و '; - - valueParts = value.split('').reverse().join('').replace(/\d{3}(?=\d)/g, "$&,").split('').reverse().join('').split(',').map(function(str) { - return Array(4 - str.length).join('0') + str; - }); - - result = (function() { - var _results; - _results = []; - for (iThree in valueParts) { - three = valueParts[iThree]; - - resultThree = (function() { - var _i, _len, _results1; - _results1 = []; - - for (i = _i = 0, _len = three.length; _i < _len; i = ++_i) { - digit = three[i]; - if (i === 1 && digit === '1') { - _results1.push(numbers.two[three[2]]); - } else if ((i !== 2 || three[1] !== '1') && numbers[i][digit] !== '') { - _results1.push(numbers[i][digit]); - } else { - continue; - } - } - - return _results1; - })(); - - resultThree = resultThree.join(delimiter); - var _result = resultThree ? resultThree + ' ' + parts[valueParts.length - parseInt(iThree) - 1] : resultThree; - _results.push(_result); + parts = [ + "", + "هزار", + "میلیون", + "میلیارد", + "تریلیون", + "کوادریلیون", + "کویینتیلیون", + "سکستیلیون", + ]; + numbers = { + 0: [ + "", + "صد", + "دویست", + "سیصد", + "چهارصد", + "پانصد", + "ششصد", + "هفتصد", + "هشتصد", + "نهصد", + ], + 1: [ + "", + "ده", + "بیست", + "سی", + "چهل", + "پنجاه", + "شصت", + "هفتاد", + "هشتاد", + "نود", + ], + 2: ["", "یک", "دو", "سه", "چهار", "پنج", "شش", "هفت", "هشت", "نه"], + two: [ + "ده", + "یازده", + "دوازده", + "سیزده", + "چهارده", + "پانزده", + "شانزده", + "هفده", + "هجده", + "نوزده", + ], + zero: "صفر", + }; + delimiter = " و "; + + valueParts = value + .split("") + .reverse() + .join("") + .replace(/\d{3}(?=\d)/g, "$&,") + .split("") + .reverse() + .join("") + .split(",") + .map(function (str) { + return Array(4 - str.length).join("0") + str; + }); + + result = (function () { + var _results; + _results = []; + for (iThree in valueParts) { + three = valueParts[iThree]; + + resultThree = (function () { + var _i, _len, _results1; + _results1 = []; + + for (i = _i = 0, _len = three.length; _i < _len; i = ++_i) { + digit = three[i]; + if (i === 1 && digit === "1") { + _results1.push(numbers.two[three[2]]); + } else if ( + (i !== 2 || three[1] !== "1") && + numbers[i][digit] !== "" + ) { + _results1.push(numbers[i][digit]); + } else { + continue; } - return _results; - })(); + } - result = result.filter(function(x) { - return x.trim() !== ''; - }); - - result = result.join(delimiter).trim(); - if (result === '') { - result = numbers.zero; - } + return _results1; + })(); - this._str = result; - return this; + resultThree = resultThree.join(delimiter); + var _result = resultThree + ? resultThree + " " + parts[valueParts.length - parseInt(iThree) - 1] + : resultThree; + _results.push(_result); + } + return _results; + })(); + + result = result.filter(function (x) { + return x.trim() !== ""; + }); + + result = result.join(delimiter).trim(); + if (result === "") { + result = numbers.zero; } - /** - * Used for Zero-width non-joiner correction - * - * @api private - * @method _halfSpace - * @param {string} value - * @return {object} PersianJs object - */ - function _halfSpace(value){ - if(!value){ - return; - } - - var pattern; - - // Replace Zero-width non-joiner between persian MI. - pattern = /((\s\u0645\u06CC)+( )+([\u0600-\u06EF]{1,}){1,})/g; - value = value.replace( new RegExp(pattern), "$2\u200C$4" ); - - // Replace Zero-width non-joiner between perisan De-Yii. - pattern = /(([\u0600-\u06EF]{1,})+( )+(ای|ایی|اند|ایم|اید|ام){1})/g; - value = value.replace( new RegExp(pattern), "$2\u200C$4" ); - - this._str = value; - return this; + this._str = result; + return this; + } + + /** + * Used for Zero-width non-joiner correction + * + * @api private + * @method _halfSpace + * @param {string} value + * @return {object} PersianJs object + */ + function _halfSpace(value) { + if (!value) { + return; } - var persianJs = function(inputStr) { - if (!inputStr || inputStr === "") { - throw new Error("Input is null or empty."); - } - return new PersianJs(inputStr); - }; + var pattern; - /** - * Current PersianJs version - * - * @property version - * @type String - */ - persianJs.version = VERSION; - - //Prototype - persianJs.fn = PersianJs.prototype = { - clone: function () { - return persianJs(this); - }, - value: function () { - return this._str; - }, - toString: function () { - return this._str.toString(); - }, - set : function (value) { - this._str = String(value); - return this; - }, - arabicChar: function() { - return _arabicChar.call(this, this._str); - }, - persianNumber: function () { - return _persianNumber.call(this, this._str); - }, - arabicNumber: function() { - return _arabicNumber.call(this, this._str); - }, - englishNumber: function() { - return _englishNumber.call(this, this._str); - }, - toEnglishNumber: function() { - return _toEnglishNumber.call(this, this._str); - }, - fixURL: function() { - return _decodeURL.call(this, this._str); - }, - decodeURL: function() { - return _decodeURL.call(this, this._str); - }, - switchKey: function() { - return _switchKey.call(this, this._str); - }, - digitsToWords: function() { - return _digitsToWords.call(this, this._str); - }, - halfSpace: function(){ - return _halfSpace.call(this, this._str); - } - }; + // Replace Zero-width non-joiner between persian MI. + pattern = /((\s\u0645\u06CC)+( )+([\u0600-\u06EF]{1,}){1,})/g; + value = value.replace(new RegExp(pattern), "$2\u200C$4"); - //Expose PersianJs - //CommonJS module is defined - if (hasModule) { - module.exports = persianJs; - } - //global ender:false - if (typeof ender === 'undefined') { - // here, `this` means `window` in the browser, or `global` on the server - // add `persianJs` as a global object via a string identifier, - // for Closure Compiler "advanced" mode - this['persianJs'] = persianJs; - } - //global define:false - if (typeof define === 'function' && define.amd) { - define('persianJs', [], function () { - return persianJs; - }); + // Replace Zero-width non-joiner between perisan De-Yii. + pattern = /(([\u0600-\u06EF]{1,})+( )+(ای|ایی|اند|ایم|اید|ام){1})/g; + value = value.replace(new RegExp(pattern), "$2\u200C$4"); + + this._str = value; + return this; + } + + var persianJs = function (inputStr) { + if (!inputStr || inputStr === "") { + throw new Error("Input is null or empty."); } + return new PersianJs(inputStr); + }; + + /** + * Current PersianJs version + * + * @property version + * @type String + */ + persianJs.version = VERSION; + + //Prototype + persianJs.fn = PersianJs.prototype = { + clone: function () { + return persianJs(this); + }, + value: function () { + return this._str; + }, + toString: function () { + return this._str.toString(); + }, + set: function (value) { + this._str = String(value); + return this; + }, + arabicChar: function () { + return _arabicChar.call(this, this._str); + }, + persianNumber: function () { + return _persianNumber.call(this, this._str); + }, + arabicNumber: function () { + return _arabicNumber.call(this, this._str); + }, + englishNumber: function () { + return _englishNumber.call(this, this._str); + }, + toEnglishNumber: function () { + return _toEnglishNumber.call(this, this._str); + }, + fixURL: function () { + return _decodeURL.call(this, this._str); + }, + decodeURL: function () { + return _decodeURL.call(this, this._str); + }, + switchKey: function () { + return _switchKey.call(this, this._str); + }, + digitsToWords: function () { + return _digitsToWords.call(this, this._str); + }, + halfSpace: function () { + return _halfSpace.call(this, this._str); + }, + }; + + //Expose PersianJs + //CommonJS module is defined + if (hasModule) { + module.exports = persianJs; + } + //global ender:false + if (typeof ender === "undefined") { + // here, `this` means `window` in the browser, or `global` on the server + // add `persianJs` as a global object via a string identifier, + // for Closure Compiler "advanced" mode + this["persianJs"] = persianJs; + } + //global define:false + if (typeof define === "function" && define.amd) { + define("persianJs", [], function () { + return persianJs; + }); + } })();