|  | /******************************************************************************* | 
|  | * You may amend and distribute as you like, but don't remove this header! | 
|  | * | 
|  | * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. | 
|  | * See http://www.codeplex.com/EPPlus for details. | 
|  | * | 
|  | * Copyright (C) 2011  Jan Källman | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  |  | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | * See the GNU Lesser General Public License for more details. | 
|  | * | 
|  | * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php | 
|  | * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html | 
|  | * | 
|  | * All code and executables are provided "as is" with no warranty either express or implied. | 
|  | * The author accepts no liability for any damage or loss of business that this product may cause. | 
|  | * | 
|  | * Code change notes: | 
|  | * | 
|  | * Author							Change						Date | 
|  | * ****************************************************************************** | 
|  | * Jan Källman		                Initial Release		        2009-10-01 | 
|  | * Jan Källman		License changed GPL-->LGPL 2011-12-16 | 
|  | *******************************************************************************/ | 
|  | using System; | 
|  | using System.Collections.Generic; | 
|  | using System.Text; | 
|  | using System.Xml; | 
|  | using System.Globalization; | 
|  | using System.Text.RegularExpressions; | 
|  | namespace OfficeOpenXml.Style.XmlAccess | 
|  | { | 
|  | /// <summary> | 
|  | /// Xml access class for number formats | 
|  | /// </summary> | 
|  | public sealed class ExcelNumberFormatXml : StyleXmlHelper | 
|  | { | 
|  | internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager) : base(nameSpaceManager) | 
|  | { | 
|  |  | 
|  | } | 
|  | internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager, bool buildIn): base(nameSpaceManager) | 
|  | { | 
|  | BuildIn = buildIn; | 
|  | } | 
|  | internal ExcelNumberFormatXml(XmlNamespaceManager nsm, XmlNode topNode) : | 
|  | base(nsm, topNode) | 
|  | { | 
|  | _numFmtId = GetXmlNodeInt("@numFmtId"); | 
|  | _format = GetXmlNodeString("@formatCode"); | 
|  | } | 
|  | public bool BuildIn { get; private set; } | 
|  | int _numFmtId; | 
|  | //        const string idPath = "@numFmtId"; | 
|  | /// <summary> | 
|  | /// Id for number format | 
|  | /// | 
|  | /// Build in ID's | 
|  | /// | 
|  | /// 0   General | 
|  | /// 1   0 | 
|  | /// 2   0.00 | 
|  | /// 3   #,##0 | 
|  | /// 4   #,##0.00 | 
|  | /// 9   0% | 
|  | /// 10  0.00% | 
|  | /// 11  0.00E+00 | 
|  | /// 12  # ?/? | 
|  | /// 13  # ??/?? | 
|  | /// 14  mm-dd-yy | 
|  | /// 15  d-mmm-yy | 
|  | /// 16  d-mmm | 
|  | /// 17  mmm-yy | 
|  | /// 18  h:mm AM/PM | 
|  | /// 19  h:mm:ss AM/PM | 
|  | /// 20  h:mm | 
|  | /// 21  h:mm:ss | 
|  | /// 22  m/d/yy h:mm | 
|  | /// 37  #,##0 ;(#,##0) | 
|  | /// 38  #,##0 ;[Red](#,##0) | 
|  | /// 39  #,##0.00;(#,##0.00) | 
|  | /// 40  #,##0.00;[Red](#,##0.00) | 
|  | /// 45  mm:ss | 
|  | /// 46  [h]:mm:ss | 
|  | /// 47  mmss.0 | 
|  | /// 48  ##0.0E+0 | 
|  | /// 49  @ | 
|  | /// </summary> | 
|  | public int NumFmtId | 
|  | { | 
|  | get | 
|  | { | 
|  | return _numFmtId; | 
|  | } | 
|  | set | 
|  | { | 
|  | _numFmtId = value; | 
|  | } | 
|  | } | 
|  | internal override string Id | 
|  | { | 
|  | get | 
|  | { | 
|  | return _format; | 
|  | } | 
|  | } | 
|  | const string fmtPath = "@formatCode"; | 
|  | string _format = string.Empty; | 
|  | public string Format | 
|  | { | 
|  | get | 
|  | { | 
|  | return _format; | 
|  | } | 
|  | set | 
|  | { | 
|  | _numFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(value); | 
|  | _format = value; | 
|  | } | 
|  | } | 
|  | internal string GetNewID(int NumFmtId, string Format) | 
|  | { | 
|  |  | 
|  | if (NumFmtId < 0) | 
|  | { | 
|  | NumFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(Format); | 
|  | } | 
|  | return NumFmtId.ToString(); | 
|  | } | 
|  |  | 
|  | internal static void AddBuildIn(XmlNamespaceManager NameSpaceManager, ExcelStyleCollection<ExcelNumberFormatXml> NumberFormats) | 
|  | { | 
|  | NumberFormats.Add("General",new ExcelNumberFormatXml(NameSpaceManager,true){NumFmtId=0,Format="General"}); | 
|  | NumberFormats.Add("0", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 1, Format = "0" }); | 
|  | NumberFormats.Add("0.00", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 2, Format = "0.00" }); | 
|  | NumberFormats.Add("#,##0", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 3, Format = "#,##0" }); | 
|  | NumberFormats.Add("#,##0.00", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 4, Format = "#,##0.00" }); | 
|  | NumberFormats.Add("0%", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 9, Format = "0%" }); | 
|  | NumberFormats.Add("0.00%", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 10, Format = "0.00%" }); | 
|  | NumberFormats.Add("0.00E+00", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 11, Format = "0.00E+00" }); | 
|  | NumberFormats.Add("# ?/?", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 12, Format = "# ?/?" }); | 
|  | NumberFormats.Add("# ??/??", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 13, Format = "# ??/??" }); | 
|  | NumberFormats.Add("mm-dd-yy", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 14, Format = "mm-dd-yy" }); | 
|  | NumberFormats.Add("d-mmm-yy", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 15, Format = "d-mmm-yy" }); | 
|  | NumberFormats.Add("d-mmm", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 16, Format = "d-mmm" }); | 
|  | NumberFormats.Add("mmm-yy", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 17, Format = "mmm-yy" }); | 
|  | NumberFormats.Add("h:mm AM/PM", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 18, Format = "h:mm AM/PM" }); | 
|  | NumberFormats.Add("h:mm:ss AM/PM", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 19, Format = "h:mm:ss AM/PM" }); | 
|  | NumberFormats.Add("h:mm", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 20, Format = "h:mm" }); | 
|  | NumberFormats.Add("h:mm:ss", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 21, Format = "h:mm:ss" }); | 
|  | NumberFormats.Add("m/d/yy h:mm", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 22, Format = "m/d/yy h:mm" }); | 
|  | NumberFormats.Add("#,##0 ;(#,##0)", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 37, Format = "#,##0 ;(#,##0)" }); | 
|  | NumberFormats.Add("#,##0 ;[Red](#,##0)", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 38, Format = "#,##0 ;[Red](#,##0)" }); | 
|  | NumberFormats.Add("#,##0.00;(#,##0.00)", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 39, Format = "#,##0.00;(#,##0.00)" }); | 
|  | NumberFormats.Add("#,##0.00;[Red](#,##0.00)", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 40, Format = "#,##0.00;[Red](#,#)" }); | 
|  | NumberFormats.Add("mm:ss", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 45, Format = "mm:ss" }); | 
|  | NumberFormats.Add("[h]:mm:ss", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 46, Format = "[h]:mm:ss" }); | 
|  | NumberFormats.Add("mmss.0", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 47, Format = "mmss.0" }); | 
|  | NumberFormats.Add("##0.0", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 48, Format = "##0.0" }); | 
|  | NumberFormats.Add("@", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 49, Format = "@" }); | 
|  |  | 
|  | NumberFormats.NextId = 164; //Start for custom formats. | 
|  | } | 
|  |  | 
|  | internal override XmlNode CreateXmlNode(XmlNode topNode) | 
|  | { | 
|  | TopNode = topNode; | 
|  | SetXmlNodeString("@numFmtId", NumFmtId.ToString()); | 
|  | SetXmlNodeString("@formatCode", Format); | 
|  | return TopNode; | 
|  | } | 
|  |  | 
|  | internal enum eFormatType | 
|  | { | 
|  | Unknown = 0, | 
|  | Number = 1, | 
|  | DateTime = 2, | 
|  | } | 
|  | ExcelFormatTranslator _translator = null; | 
|  | internal ExcelFormatTranslator FormatTranslator | 
|  | { | 
|  | get | 
|  | { | 
|  | if (_translator == null) | 
|  | { | 
|  | _translator = new ExcelFormatTranslator(Format, NumFmtId); | 
|  | } | 
|  | return _translator; | 
|  | } | 
|  | } | 
|  | #region Excel --> .Net Format | 
|  | internal class ExcelFormatTranslator | 
|  | { | 
|  | internal ExcelFormatTranslator(string format, int numFmtID) | 
|  | { | 
|  | if (numFmtID == 14) | 
|  | { | 
|  | NetFormat = NetFormatForWidth = "d"; | 
|  | NetTextFormat = NetTextFormatForWidth = ""; | 
|  | DataType = eFormatType.DateTime; | 
|  | } | 
|  | else if (format.Equals("general",StringComparison.InvariantCultureIgnoreCase)) | 
|  | { | 
|  | NetFormat = NetFormatForWidth = "0.#####"; | 
|  | NetTextFormat = NetTextFormatForWidth = ""; | 
|  | DataType = eFormatType.Number; | 
|  | } | 
|  | else | 
|  | { | 
|  | ToNetFormat(format, false); | 
|  | ToNetFormat(format, true); | 
|  | } | 
|  | } | 
|  | internal string NetTextFormat { get; private set; } | 
|  | internal string NetFormat { get; private set; } | 
|  | CultureInfo _ci = null; | 
|  | internal CultureInfo Culture | 
|  | { | 
|  | get | 
|  | { | 
|  | if (_ci == null) | 
|  | { | 
|  | return CultureInfo.CurrentCulture; | 
|  | } | 
|  | return _ci; | 
|  | } | 
|  | private set | 
|  | { | 
|  | _ci = value; | 
|  | } | 
|  | } | 
|  | internal eFormatType DataType { get; private set; } | 
|  | internal string NetTextFormatForWidth { get; private set; } | 
|  | internal string NetFormatForWidth { get; private set; } | 
|  |  | 
|  | //internal string FractionFormatInteger { get; private set; } | 
|  | internal string FractionFormat { get; private set; } | 
|  | //internal string FractionFormat2 { get; private set; } | 
|  |  | 
|  | private void ToNetFormat(string ExcelFormat, bool forColWidth) | 
|  | { | 
|  | DataType = eFormatType.Unknown; | 
|  | int secCount = 0; | 
|  | bool isText = false; | 
|  | bool isBracket = false; | 
|  | string bracketText = ""; | 
|  | bool prevBslsh = false; | 
|  | bool useMinute = false; | 
|  | bool prevUnderScore = false; | 
|  | bool ignoreNext = false; | 
|  | int fractionPos = -1; | 
|  | string specialDateFormat = ""; | 
|  | bool containsAmPm = ExcelFormat.Contains("AM/PM"); | 
|  | List<int> lstDec=new List<int>(); | 
|  | StringBuilder sb = new StringBuilder(); | 
|  | Culture = null; | 
|  | var format = ""; | 
|  | var text = ""; | 
|  | char clc; | 
|  |  | 
|  | if (containsAmPm) | 
|  | { | 
|  | ExcelFormat = Regex.Replace(ExcelFormat, "AM/PM", ""); | 
|  | DataType = eFormatType.DateTime; | 
|  | } | 
|  |  | 
|  | for (int pos = 0; pos < ExcelFormat.Length; pos++) | 
|  | { | 
|  | char c = ExcelFormat[pos]; | 
|  | if (c == '"') | 
|  | { | 
|  | isText = !isText; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (ignoreNext) | 
|  | { | 
|  | ignoreNext = false; | 
|  | continue; | 
|  | } | 
|  | else if (isText && !isBracket) | 
|  | { | 
|  | sb.Append(c); | 
|  | } | 
|  | else if (isBracket) | 
|  | { | 
|  | if (c == ']') | 
|  | { | 
|  | isBracket = false; | 
|  | if (bracketText[0] == '$')  //Local Info | 
|  | { | 
|  | string[] li = Regex.Split(bracketText, "-"); | 
|  | if (li[0].Length > 1) | 
|  | { | 
|  | sb.Append("\"" + li[0].Substring(1, li[0].Length - 1) + "\"");     //Currency symbol | 
|  | } | 
|  | if (li.Length > 1) | 
|  | { | 
|  | if (li[1].Equals("f800", StringComparison.InvariantCultureIgnoreCase)) | 
|  | { | 
|  | specialDateFormat = "D"; | 
|  | } | 
|  | else if (li[1].Equals("f400", StringComparison.InvariantCultureIgnoreCase)) | 
|  | { | 
|  | specialDateFormat = "T"; | 
|  | } | 
|  | else | 
|  | { | 
|  | var num = int.Parse(li[1], NumberStyles.HexNumber); | 
|  | try | 
|  | { | 
|  | Culture = CultureInfo.GetCultureInfo(num & 0xFFFF); | 
|  | } | 
|  | catch | 
|  | { | 
|  | Culture = null; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | else if(bracketText[0]=='t') | 
|  | { | 
|  | sb.Append("hh"); //TODO:This will not be correct for dates over 24H. | 
|  | } | 
|  | else if (bracketText[0] == 'h') | 
|  | { | 
|  | specialDateFormat = "hh"; //TODO:This will not be correct for dates over 24H. | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | bracketText += c; | 
|  | } | 
|  | } | 
|  | else if (prevUnderScore) | 
|  | { | 
|  | if (forColWidth) | 
|  | { | 
|  | sb.AppendFormat("\"{0}\"", c); | 
|  | } | 
|  | prevUnderScore = false; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (c == ';') //We use first part (for positive only at this stage) | 
|  | { | 
|  | secCount++; | 
|  | if (DataType == eFormatType.DateTime || secCount == 3) | 
|  | { | 
|  | //Add qoutes | 
|  | if (DataType == eFormatType.DateTime) SetDecimal(lstDec, sb); //Remove? | 
|  | lstDec = new List<int>(); | 
|  | format = sb.ToString(); | 
|  | sb = new StringBuilder(); | 
|  | } | 
|  | else | 
|  | { | 
|  | sb.Append(c); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | clc = c.ToString().ToLower(CultureInfo.InvariantCulture)[0];  //Lowercase character | 
|  | //Set the datetype | 
|  | if (DataType == eFormatType.Unknown) | 
|  | { | 
|  | if (c == '0' || c == '#' || c == '.') | 
|  | { | 
|  | DataType = eFormatType.Number; | 
|  | } | 
|  | else if (clc == 'y' || clc == 'm' || clc == 'd' || clc == 'h' || clc == 'm' || clc == 's') | 
|  | { | 
|  | DataType = eFormatType.DateTime; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (prevBslsh) | 
|  | { | 
|  | if (c == '.' || c == ',') | 
|  | { | 
|  | sb.Append('\\'); | 
|  | } | 
|  | sb.Append(c); | 
|  | prevBslsh = false; | 
|  | } | 
|  | else if (c == '[') | 
|  | { | 
|  | bracketText = ""; | 
|  | isBracket = true; | 
|  | } | 
|  | else if (c == '\\') | 
|  | { | 
|  | prevBslsh = true; | 
|  | } | 
|  | else if (c == '0' || | 
|  | c == '#' || | 
|  | c == '.' || | 
|  | c == ',' || | 
|  | c == '%' || | 
|  | clc == 'd' || | 
|  | clc == 's') | 
|  | { | 
|  | sb.Append(c); | 
|  | if(c=='.') | 
|  | { | 
|  | lstDec.Add(sb.Length - 1); | 
|  | } | 
|  | } | 
|  | else if (clc == 'h') | 
|  | { | 
|  | if (containsAmPm) | 
|  | { | 
|  | sb.Append('h'); ; | 
|  | } | 
|  | else | 
|  | { | 
|  | sb.Append('H'); | 
|  | } | 
|  | useMinute = true; | 
|  | } | 
|  | else if (clc == 'm') | 
|  | { | 
|  | if (useMinute) | 
|  | { | 
|  | sb.Append('m'); | 
|  | } | 
|  | else | 
|  | { | 
|  | sb.Append('M'); | 
|  | } | 
|  | } | 
|  | else if (c == '_') //Skip next but use for alignment | 
|  | { | 
|  | prevUnderScore = true; | 
|  | } | 
|  | else if (c == '?') | 
|  | { | 
|  | sb.Append(' '); | 
|  | } | 
|  | else if (c == '/') | 
|  | { | 
|  | if (DataType == eFormatType.Number) | 
|  | { | 
|  | fractionPos = sb.Length; | 
|  | int startPos = pos - 1; | 
|  | while (startPos >= 0 && | 
|  | (ExcelFormat[startPos] == '?' || | 
|  | ExcelFormat[startPos] == '#' || | 
|  | ExcelFormat[startPos] == '0')) | 
|  | { | 
|  | startPos--; | 
|  | } | 
|  |  | 
|  | if (startPos > 0)  //RemovePart | 
|  | sb.Remove(sb.Length-(pos-startPos-1),(pos-startPos-1)) ; | 
|  |  | 
|  | int endPos = pos + 1; | 
|  | while (endPos < ExcelFormat.Length && | 
|  | (ExcelFormat[endPos] == '?' || | 
|  | ExcelFormat[endPos] == '#' || | 
|  | (ExcelFormat[endPos] >= '0' && ExcelFormat[endPos]<= '9'))) | 
|  | { | 
|  | endPos++; | 
|  | } | 
|  | pos = endPos; | 
|  | if (FractionFormat != "") | 
|  | { | 
|  | FractionFormat = ExcelFormat.Substring(startPos+1, endPos - startPos-1); | 
|  | } | 
|  | sb.Append('?'); //Will be replaced later on by the fraction | 
|  | } | 
|  | else | 
|  | { | 
|  | sb.Append('/'); | 
|  | } | 
|  | } | 
|  | else if (c == '*') | 
|  | { | 
|  | //repeat char--> ignore | 
|  | ignoreNext = true; | 
|  | } | 
|  | else if (c == '@') | 
|  | { | 
|  | sb.Append("{0}"); | 
|  | } | 
|  | else | 
|  | { | 
|  | sb.Append(c); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | //Add qoutes | 
|  | if (DataType == eFormatType.DateTime) SetDecimal(lstDec, sb); //Remove? | 
|  |  | 
|  | // AM/PM format | 
|  | if (containsAmPm) | 
|  | { | 
|  | format += "tt"; | 
|  | } | 
|  |  | 
|  |  | 
|  | if (format == "") | 
|  | format = sb.ToString(); | 
|  | else | 
|  | text = sb.ToString(); | 
|  | if (specialDateFormat != "") | 
|  | { | 
|  | format = specialDateFormat; | 
|  | } | 
|  |  | 
|  | if (forColWidth) | 
|  | { | 
|  | NetFormatForWidth = format; | 
|  | NetTextFormatForWidth = text; | 
|  | } | 
|  | else | 
|  | { | 
|  | NetFormat = format; | 
|  | NetTextFormat = text; | 
|  | } | 
|  | if (Culture == null) | 
|  | { | 
|  | Culture = CultureInfo.CurrentCulture; | 
|  | } | 
|  | } | 
|  |  | 
|  | private static void SetDecimal(List<int> lstDec, StringBuilder sb) | 
|  | { | 
|  | if (lstDec.Count > 1) | 
|  | { | 
|  | for (int i = lstDec.Count - 1; i >= 0; i--) | 
|  | { | 
|  | sb.Insert(lstDec[i] + 1, '\''); | 
|  | sb.Insert(lstDec[i], '\''); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | internal string FormatFraction(double d) | 
|  | { | 
|  | int numerator, denomerator; | 
|  |  | 
|  | int intPart = (int)d; | 
|  |  | 
|  | string[] fmt = FractionFormat.Split('/'); | 
|  |  | 
|  | int fixedDenominator; | 
|  | if (!int.TryParse(fmt[1], out fixedDenominator)) | 
|  | { | 
|  | fixedDenominator = 0; | 
|  | } | 
|  |  | 
|  | if (d == 0 || double.IsNaN(d)) | 
|  | { | 
|  | if (fmt[0].Trim() == "" && fmt[1].Trim() == "") | 
|  | { | 
|  | return new string(' ', FractionFormat.Length); | 
|  | } | 
|  | else | 
|  | { | 
|  | return 0.ToString(fmt[0]) + "/" + 1.ToString(fmt[0]); | 
|  | } | 
|  | } | 
|  |  | 
|  | int maxDigits = fmt[1].Length; | 
|  | string sign = d < 0 ? "-" : ""; | 
|  | if (fixedDenominator == 0) | 
|  | { | 
|  | List<double> numerators = new List<double>() { 1, 0 }; | 
|  | List<double> denominators = new List<double>() { 0, 1 }; | 
|  |  | 
|  | if (maxDigits < 1 && maxDigits > 12) | 
|  | { | 
|  | throw (new ArgumentException("Number of digits out of range (1-12)")); | 
|  | } | 
|  |  | 
|  | int maxNum = 0; | 
|  | for (int i = 0; i < maxDigits; i++) | 
|  | { | 
|  | maxNum += 9 * (int)(Math.Pow((double)10, (double)i)); | 
|  | } | 
|  |  | 
|  | double divRes = 1 / ((double)Math.Abs(d) - intPart); | 
|  | double result, prevResult = double.NaN; | 
|  | int listPos = 2, index = 1; | 
|  | while (true) | 
|  | { | 
|  | index++; | 
|  | double intDivRes = Math.Floor(divRes); | 
|  | numerators.Add((intDivRes * numerators[index - 1] + numerators[index - 2])); | 
|  | if (numerators[index] > maxNum) | 
|  | { | 
|  | break; | 
|  | } | 
|  |  | 
|  | denominators.Add((intDivRes * denominators[index - 1] + denominators[index - 2])); | 
|  |  | 
|  | result = numerators[index] / denominators[index]; | 
|  | if (denominators[index] > maxNum) | 
|  | { | 
|  | break; | 
|  | } | 
|  | listPos = index; | 
|  |  | 
|  | if (result == prevResult) break; | 
|  |  | 
|  | if (result == d) break; | 
|  |  | 
|  | prevResult = result; | 
|  |  | 
|  | divRes = 1 / (divRes - intDivRes);  //Rest | 
|  | } | 
|  |  | 
|  | numerator = (int)numerators[listPos]; | 
|  | denomerator = (int)denominators[listPos]; | 
|  | } | 
|  | else | 
|  | { | 
|  | numerator = (int)Math.Round((d - intPart) / (1D / fixedDenominator), 0); | 
|  | denomerator = fixedDenominator; | 
|  | } | 
|  | if (numerator == denomerator || numerator==0) | 
|  | { | 
|  | if(numerator == denomerator) intPart++; | 
|  | return sign + intPart.ToString(NetFormat).Replace("?", new string(' ', FractionFormat.Length)); | 
|  | } | 
|  | else if (intPart == 0) | 
|  | { | 
|  | return sign + FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1]); | 
|  | } | 
|  | else | 
|  | { | 
|  | return sign + intPart.ToString(NetFormat).Replace("?", FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1])); | 
|  | } | 
|  | } | 
|  |  | 
|  | private string FmtInt(double value, string format) | 
|  | { | 
|  | string v = value.ToString("#"); | 
|  | string pad = ""; | 
|  | if (v.Length < format.Length) | 
|  | { | 
|  | for (int i = format.Length - v.Length-1; i >= 0; i--) | 
|  | { | 
|  | if (format[i] == '?') | 
|  | { | 
|  | pad += " "; | 
|  | } | 
|  | else if (format[i] == ' ') | 
|  | { | 
|  | pad += "0"; | 
|  | } | 
|  | } | 
|  | } | 
|  | return pad + v; | 
|  | } | 
|  | } | 
|  | #endregion | 
|  | } | 
|  | } |