Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/ExcelCellBase.cs @ 12074

Last change on this file since 12074 was 12074, checked in by sraggl, 9 years ago

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 36.4 KB
Line 
1/*******************************************************************************
2 * You may amend and distribute as you like, but don't remove this header!
3 *
4 * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
5 * See http://www.codeplex.com/EPPlus for details.
6 *
7 * Copyright (C) 2011  Jan Källman
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
17 * See the GNU Lesser General Public License for more details.
18 *
19 * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
20 * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
21 *
22 * All code and executables are provided "as is" with no warranty either express or implied.
23 * The author accepts no liability for any damage or loss of business that this product may cause.
24 *
25 * Code change notes:
26 *
27 * Author             Change            Date
28 *******************************************************************************
29 * Jan Källman    Initial Release           2009-10-01
30 * Jan Källman    License changed GPL-->LGPL 2011-12-27
31 *******************************************************************************/
32using System;
33using System.Collections.Generic;
34using System.Globalization;
35using System.Text;
36using OfficeOpenXml.Style;
37using System.Text.RegularExpressions;
38using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
39using System.Linq;
40using OfficeOpenXml.FormulaParsing.Excel.Functions;
41using OfficeOpenXml.FormulaParsing;
42namespace OfficeOpenXml
43{
44    /// <summary>
45    /// Base class containing cell address manipulating methods.
46    /// </summary>
47    public abstract class ExcelCellBase
48    {
49        #region "public functions"
50        /// <summary>
51        /// Get the sheet, row and column from the CellID
52        /// </summary>
53        /// <param name="cellID"></param>
54        /// <param name="sheet"></param>
55        /// <param name="row"></param>
56        /// <param name="col"></param>
57        static internal void SplitCellID(ulong cellID, out int sheet, out int row, out int col)
58        {
59            sheet = (int)(cellID % 0x8000);
60            col = ((int)(cellID >> 15) & 0x3FF);
61            row = ((int)(cellID >> 29));
62        }
63        /// <summary>
64        /// Get the cellID for the cell.
65        /// </summary>
66        /// <param name="SheetID"></param>
67        /// <param name="row"></param>
68        /// <param name="col"></param>
69        /// <returns></returns>
70        internal static ulong GetCellID(int SheetID, int row, int col)
71        {
72            return ((ulong)SheetID) + (((ulong)col) << 15) + (((ulong)row) << 29);
73        }
74        #endregion
75        #region "Formula Functions"
76        private delegate string dlgTransl(string part, int row, int col, int rowIncr, int colIncr);
77        #region R1C1 Functions"
78        /// <summary>
79        /// Translates a R1C1 to an absolut address/Formula
80        /// </summary>
81        /// <param name="value">Address</param>
82        /// <param name="row">Current row</param>
83        /// <param name="col">Current column</param>
84        /// <returns>The RC address</returns>
85        public static string TranslateFromR1C1(string value, int row, int col)
86        {
87            return Translate(value, ToAbs, row, col, -1, -1);
88        }
89        /// <summary>
90        /// Translates a absolut address to R1C1 Format
91        /// </summary>
92        /// <param name="value">R1C1 Address</param>
93        /// <param name="row">Current row</param>
94        /// <param name="col">Current column</param>
95        /// <returns>The absolut address/Formula</returns>
96        public static string TranslateToR1C1(string value, int row, int col)
97        {
98            return Translate(value, ToR1C1, row, col, -1, -1);
99        }
100        /// <summary>
101        /// Translates betweein R1C1 or absolut addresses
102        /// </summary>
103        /// <param name="value">The addresss/function</param>
104        /// <param name="addressTranslator">The translating function</param>
105        /// <param name="row"></param>
106        /// <param name="col"></param>
107        /// <param name="rowIncr"></param>
108        /// <param name="colIncr"></param>
109        /// <returns></returns>
110        private static string Translate(string value, dlgTransl addressTranslator, int row, int col, int rowIncr, int colIncr)
111        {
112            if (value == "")
113                return "";
114            bool isText = false;
115            string ret = "";
116            string part = "";
117            char prevTQ = (char)0;
118            for (int pos = 0; pos < value.Length; pos++)
119            {
120                char c = value[pos];
121                if (c == '"' || c=='\'')
122                {
123                    if (isText == false && part != "" && prevTQ==c)
124                    {
125                        ret += addressTranslator(part, row, col, rowIncr, colIncr);
126                        part = "";
127                        prevTQ = (char)0;
128                    }
129                    prevTQ = c;
130                    isText = !isText;
131                    ret += c;
132                }
133                else if (isText)
134                {
135                    ret += c;
136                }
137                else
138                {
139                    if ((c == '-' || c == '+' || c == '*' || c == '/' ||
140                        c == '=' || c == '^' || c == ',' || c == ':' ||
141                        c == '<' || c == '>' || c == '(' || c == ')' || c == '!' ||
142                        c == ' ' || c == '&' || c == '%') &&
143                        (pos == 0 || value[pos - 1] != '[')) //Last part to allow for R1C1 style [-x]
144                    {
145                        ret += addressTranslator(part, row, col, rowIncr, colIncr) + c;
146                        part = "";
147                    }
148                    else
149                    {
150                        part += c;
151                    }
152                }
153            }
154            if (part != "")
155            {
156                ret += addressTranslator(part, row, col, rowIncr, colIncr);
157            }
158            return ret;
159        }
160        /// <summary>
161        /// Translate to R1C1
162        /// </summary>
163        /// <param name="part">the value to be translated</param>
164        /// <param name="row"></param>
165        /// <param name="col"></param>
166        /// <param name="rowIncr"></param>
167        /// <param name="colIncr"></param>
168        /// <returns></returns>
169        private static string ToR1C1(string part, int row, int col, int rowIncr, int colIncr)
170        {
171            int addrRow, addrCol;
172            string Ret = "R";
173            if (GetRowCol(part, out addrRow, out addrCol, false))
174            {
175                if (addrRow == 0 || addrCol == 0)
176                {
177                    return part;
178                }
179                if (part.IndexOf('$', 1) > 0)
180                {
181                    Ret += addrRow.ToString();
182                }
183                else if (addrRow - row != 0)
184                {
185                    Ret += string.Format("[{0}]", addrRow - row);
186                }
187
188                if (part.StartsWith("$"))
189                {
190                    return Ret + "C" + addrCol;
191                }
192                else if (addrCol - col != 0)
193                {
194                    return Ret + "C" + string.Format("[{0}]", addrCol - col);
195                }
196                else
197                {
198                    return Ret + "C";
199                }
200            }
201            else
202            {
203                return part;
204            }
205        }
206        /// <summary>
207        /// Translates to absolute address
208        /// </summary>
209        /// <param name="part"></param>
210        /// <param name="row"></param>
211        /// <param name="col"></param>
212        /// <param name="rowIncr"></param>
213        /// <param name="colIncr"></param>
214        /// <returns></returns>
215        private static string ToAbs(string part, int row, int col, int rowIncr, int colIncr)
216        {
217            string check = part.ToUpper(CultureInfo.InvariantCulture);
218
219            int rStart = check.IndexOf("R");
220            if (rStart != 0)
221                return part;
222            if (part.Length == 1) //R
223            {
224                return GetAddress(row, col);
225            }
226
227            int cStart = check.IndexOf("C");
228            bool absoluteRow, absoluteCol;
229            if (cStart == -1)
230            {
231                int RNum = GetRC(part, row, out absoluteRow);
232                if (RNum > int.MinValue)
233                {
234                    return GetAddress(RNum, absoluteRow, col, false);
235                }
236                else
237                {
238                    return part;
239                }
240            }
241            else
242            {
243                int RNum = GetRC(part.Substring(1, cStart - 1), row, out absoluteRow);
244                int CNum = GetRC(part.Substring(cStart + 1, part.Length - cStart - 1), col, out absoluteCol);
245                if (RNum > int.MinValue && CNum > int.MinValue)
246                {
247                    return GetAddress(RNum, absoluteRow, CNum, absoluteCol);
248                }
249                else
250                {
251                    return part;
252                }
253            }
254        }
255        /// <summary>
256        /// Adds or subtracts a row or column to an address
257        /// </summary>
258        /// <param name="Address"></param>
259        /// <param name="row"></param>
260        /// <param name="col"></param>
261        /// <param name="rowIncr"></param>
262        /// <param name="colIncr"></param>
263        /// <returns></returns>
264        private static string AddToRowColumnTranslator(string Address, int row, int col, int rowIncr, int colIncr)
265        {
266            int fromRow, fromCol;
267            if (Address == "#REF!")
268            {
269                return Address;
270            }
271            if (GetRowCol(Address, out fromRow, out fromCol, false))
272            {
273                if (fromRow == 0 || fromCol == 0)
274                {
275                    return Address;
276                }
277                if (rowIncr != 0 && row != 0 && fromRow >= row && Address.IndexOf('$', 1) == -1)
278                {
279                    if (fromRow < row - rowIncr)
280                    {
281                        return "#REF!";
282                    }
283
284                    fromRow = fromRow + rowIncr;
285                }
286
287                if (colIncr != 0 && col != 0 && fromCol >= col && Address.StartsWith("$") == false)
288                {
289                    if (fromCol < col - colIncr)
290                    {
291                        return "#REF!";
292                    }
293
294                    fromCol = fromCol + colIncr;
295                }
296
297                Address = GetAddress(fromRow, Address.IndexOf('$', 1) > -1, fromCol, Address.StartsWith("$"));
298            }
299            return Address;
300        }
301
302        /// <summary>
303        /// Returns with brackets if the value is negative
304        /// </summary>
305        /// <param name="v">The value</param>
306        /// <returns></returns>
307        private static string GetRCFmt(int v)
308        {
309            return (v < 0 ? string.Format("[{0}]", v) : v > 0 ? v.ToString() : "");
310        }
311        /// <summary>
312        /// Get the offset value for RC format
313        /// </summary>
314        /// <param name="value"></param>
315        /// <param name="OffsetValue"></param>
316        /// <param name="fixedAddr"></param>
317        /// <returns></returns>
318        private static int GetRC(string value, int OffsetValue, out bool fixedAddr)
319        {
320            if (value == "")
321            {
322                fixedAddr = false;
323                return OffsetValue;
324            }
325            int num;
326            if (value[0] == '[' && value[value.Length - 1] == ']') //Offset?               
327            {
328                fixedAddr = false;
329                if (int.TryParse(value.Substring(1, value.Length - 2), out num))
330                {
331                    return (OffsetValue + num);
332                }
333                else
334                {
335                    return int.MinValue;
336                }
337            }
338            else
339            {
340                fixedAddr = true;
341                if (int.TryParse(value, out num))
342                {
343                    return num;
344                }
345                else
346                {
347                    return int.MinValue;
348                }
349            }
350        }
351        #endregion
352        #region "Address Functions"
353        #region GetColumnLetter
354        /// <summary>
355        /// Returns the character representation of the numbered column
356        /// </summary>
357        /// <param name="iColumnNumber">The number of the column</param>
358        /// <returns>The letter representing the column</returns>
359        protected internal static string GetColumnLetter(int iColumnNumber)
360        {
361            return GetColumnLetter(iColumnNumber, false);
362        }
363        protected internal static string GetColumnLetter(int iColumnNumber, bool fixedCol)
364        {
365
366            if (iColumnNumber < 1)
367            {
368                //throw new Exception("Column number is out of range");
369                return "#REF!";
370            }
371
372            string sCol = "";
373            do
374            {
375                sCol = ((char)('A' + ((iColumnNumber - 1) % 26))) + sCol;
376                iColumnNumber = (iColumnNumber - ((iColumnNumber - 1) % 26)) / 26;
377            }
378            while (iColumnNumber > 0);
379            return fixedCol ? "$" + sCol : sCol;
380        }
381        #endregion
382
383        internal static bool GetRowColFromAddress(string CellAddress, out int FromRow, out int FromColumn, out int ToRow, out int ToColumn)
384        {
385            bool fixedFromRow, fixedFromColumn, fixedToRow, fixedToColumn;
386            return GetRowColFromAddress(CellAddress, out FromRow, out FromColumn, out ToRow, out ToColumn, out fixedFromRow, out fixedFromColumn, out fixedToRow, out fixedToColumn);
387        }
388        /// <summary>
389        /// Get the row/columns for a Cell-address
390        /// </summary>
391        /// <param name="CellAddress">The address</param>
392        /// <param name="FromRow">Returns the to column</param>
393        /// <param name="FromColumn">Returns the from column</param>
394        /// <param name="ToRow">Returns the to row</param>
395        /// <param name="ToColumn">Returns the from row</param>
396        /// <param name="fixedFromRow">Is the from row fixed?</param>
397        /// <param name="fixedFromColumn">Is the from column fixed?</param>
398        /// <param name="fixedToRow">Is the to row fixed?</param>
399        /// <param name="fixedToColumn">Is the to column fixed?</param>
400        /// <returns></returns>
401        internal static bool GetRowColFromAddress(string CellAddress, out int FromRow, out int FromColumn, out int ToRow, out int ToColumn, out bool fixedFromRow, out bool fixedFromColumn, out bool fixedToRow, out bool fixedToColumn)
402        {
403            bool ret;
404            if (CellAddress.IndexOf('[') > 0) //External reference or reference to Table or Pivottable.
405            {
406                FromRow = -1;
407                FromColumn = -1;
408                ToRow = -1;
409                ToColumn = -1;
410                fixedFromRow = false;
411                fixedFromColumn = false;
412                fixedToRow= false;
413                fixedToColumn = false;
414                return false;
415            }
416
417            CellAddress = CellAddress.ToUpper(CultureInfo.InvariantCulture);
418            //This one can be removed when the worksheet Select format is fixed
419            if (CellAddress.IndexOf(' ') > 0)
420            {
421                CellAddress = CellAddress.Substring(0, CellAddress.IndexOf(' '));
422            }
423
424            if (CellAddress.IndexOf(':') < 0)
425            {
426                ret = GetRowColFromAddress(CellAddress, out FromRow, out FromColumn, out fixedFromRow, out fixedFromColumn);
427                ToColumn = FromColumn;
428                ToRow = FromRow;
429                fixedToRow = fixedFromRow;
430                fixedToColumn = fixedFromColumn;
431            }
432            else
433            {
434                string[] cells = CellAddress.Split(':');
435                ret = GetRowColFromAddress(cells[0], out FromRow, out FromColumn, out fixedFromRow, out fixedFromColumn);
436                if (ret)
437                    ret = GetRowColFromAddress(cells[1], out ToRow, out ToColumn, out fixedToRow, out fixedToColumn);
438                else
439                {
440                    GetRowColFromAddress(cells[1], out ToRow, out ToColumn, out fixedToRow, out fixedToColumn);
441                }
442
443                if (FromColumn <= 0)
444                    FromColumn = 1;
445                if (FromRow <= 0)
446                    FromRow = 1;
447                if (ToColumn <= 0)
448                    ToColumn = ExcelPackage.MaxColumns;
449                if (ToRow <= 0)
450                    ToRow = ExcelPackage.MaxRows;
451            }
452            return ret;
453        }
454        /// <summary>
455        /// Get the row/column for n Cell-address
456        /// </summary>
457        /// <param name="CellAddress">The address</param>
458        /// <param name="Row">Returns Tthe row</param>
459        /// <param name="Column">Returns the column</param>
460        /// <returns>true if valid</returns>
461        internal static bool GetRowColFromAddress(string CellAddress, out int Row, out int Column)
462        {
463            return GetRowCol(CellAddress, out Row, out Column, true);
464        }
465        internal static bool GetRowColFromAddress(string CellAddress, out int row, out int col, out bool fixedRow, out bool fixedCol)
466        {
467            return GetRowCol(CellAddress, out row, out col, true, out fixedRow, out fixedCol);
468        }
469
470        /// <summary>
471        /// Get the row/column for a Cell-address
472        /// </summary>
473        /// <param name="address">the address</param>
474        /// <param name="row">returns the row</param>
475        /// <param name="col">returns the column</param>
476        /// <param name="throwException">throw exception if invalid, otherwise returns false</param>
477        /// <returns></returns>
478        internal static bool GetRowCol(string address, out int row, out int col, bool throwException)
479        {
480            bool fixedRow, fixedCol;
481            return GetRowCol(address, out row, out col, throwException, out fixedRow, out fixedCol);
482        }
483        internal static bool GetRowCol(string address, out int row, out int col, bool throwException, out bool fixedRow, out bool fixedCol)
484        {
485            bool colPart = true;
486            string sRow = "", sCol = "";
487            col = 0;
488            fixedRow = false;
489            fixedCol = false;
490            if (address.IndexOf(':') > 0)  //If it is a mult-cell address use
491            {
492                address = address.Substring(0, address.IndexOf(':'));
493            }
494            if (address.EndsWith("#REF!"))
495            {
496                row = 0;
497                col = 0;
498                return true;
499            }
500
501            int sheetMarkerIndex = address.IndexOf('!');
502            if (sheetMarkerIndex >= 0)
503            {
504                address = address.Substring(sheetMarkerIndex + 1);
505            }
506
507            address = address.ToUpper(CultureInfo.InvariantCulture);
508            for (int i = 0; i < address.Length; i++)
509            {
510                if ((address[i] >= 'A' && address[i] <= 'Z') && colPart && sCol.Length <= 3)
511                {
512                    sCol += address[i];
513                }
514                else if (address[i] >= '0' && address[i] <= '9')
515                {
516                    sRow += address[i];
517                    colPart = false;
518                }
519                else if (address[i] == '$')
520                {
521                    if (i == 0)
522                        fixedCol = true;
523                    else
524                        fixedRow = true;
525                }
526                else
527                {
528                    if (throwException)
529                    {
530                        throw (new Exception(string.Format("Invalid Address format {0}", address)));
531                    }
532                    else
533                    {
534                        row = 0;
535                        col = 0;
536                        return false;
537                    }
538                }
539            }
540
541            // Get the column number
542            if (sCol != "")
543            {
544                col = GetColumn(sCol);
545            }
546            else
547            {
548                col = 0;
549                int.TryParse(sRow, out row);
550                return row>0;
551            }
552            // Get the row number
553            if (sRow == "") //Blank, fullRow
554            {
555                //if (throwException)
556                //{
557                //    throw (new Exception(string.Format("Invalid Address format {0}", address)));
558                //}
559                //else
560                //{                   
561                row = 0;
562                return col > 0;
563                //}
564            }
565            else
566            {
567                return int.TryParse(sRow, out row);
568            }
569        }
570
571        private static int GetColumn(string sCol)
572        {
573            int col = 0;
574            int len = sCol.Length - 1;
575            for (int i = len; i >= 0; i--)
576            {
577                col += (((int)sCol[i]) - 64) * (int)(Math.Pow(26, len - i));
578            }
579            return col;
580        }
581        #region GetAddress
582        /// <summary>
583        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
584        /// </summary>
585        /// <param name="Row">The number of the row</param>
586        /// <param name="Column">The number of the column in the worksheet</param>
587        /// <returns>The cell address in the format A1</returns>
588        public static string GetAddress(int Row, int Column)
589        {
590            return GetAddress(Row, Column,false);
591        }
592        /// <summary>
593        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
594        /// </summary>
595        /// <param name="Row">The number of the row</param>
596        /// <param name="Column">The number of the column in the worksheet</param>
597        /// <param name="AbsoluteRow">Absolute row</param>
598        /// <param name="AbsoluteCol">Absolute column</param>
599        /// <returns>The cell address in the format A1</returns>
600        public static string GetAddress(int Row, bool AbsoluteRow, int Column, bool AbsoluteCol)
601        {
602            return ( AbsoluteCol ? "$" : "") + GetColumnLetter(Column) + ( AbsoluteRow ? "$" : "") + Row.ToString();
603        }
604        /// <summary>
605        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
606        /// </summary>
607        /// <param name="Row">The number of the row</param>
608        /// <param name="Column">The number of the column in the worksheet</param>
609        /// <param name="Absolute">Get an absolute address ($A$1)</param>
610        /// <returns>The cell address in the format A1</returns>
611        public static string GetAddress(int Row, int Column, bool Absolute)
612        {
613            if (Row == 0 || Column == 0)
614            {
615                return "#REF!";
616            }
617            if (Absolute)
618            {
619                return ("$" + GetColumnLetter(Column) + "$" + Row.ToString());
620            }
621            else
622            {
623                return (GetColumnLetter(Column) + Row.ToString());
624            }
625        }
626        /// <summary>
627        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
628        /// </summary>
629        /// <param name="FromRow">From row number</param>
630        /// <param name="FromColumn">From column number</param>
631        /// <param name="ToRow">To row number</param>
632        /// <param name="ToColumn">From column number</param>
633        /// <returns>The cell address in the format A1</returns>
634        public static string GetAddress(int FromRow, int FromColumn, int ToRow, int ToColumn)
635        {
636            return GetAddress(FromRow, FromColumn, ToRow, ToColumn, false);
637        }
638        /// <summary>
639        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
640        /// </summary>
641        /// <param name="FromRow">From row number</param>
642        /// <param name="FromColumn">From column number</param>
643        /// <param name="ToRow">To row number</param>
644        /// <param name="ToColumn">From column number</param>
645        /// <param name="Absolute">if true address is absolute (like $A$1)</param>
646        /// <returns>The cell address in the format A1</returns>
647        public static string GetAddress(int FromRow, int FromColumn, int ToRow, int ToColumn, bool Absolute)
648        {
649            if (FromRow == ToRow && FromColumn == ToColumn)
650            {
651                return GetAddress(FromRow, FromColumn, Absolute);
652            }
653            else
654            {
655                if (FromRow == 1 && ToRow == ExcelPackage.MaxRows)
656                {
657                    var absChar = Absolute ? "$" : "";
658                    return absChar + GetColumnLetter(FromColumn) + ":" + absChar + GetColumnLetter(ToColumn);
659                }
660                else if(FromColumn==1 && ToColumn==ExcelPackage.MaxColumns)
661                {
662                    var absChar = Absolute ? "$" : "";
663                    return absChar + FromRow.ToString() + ":" + absChar + ToRow.ToString();
664                }
665                else
666                {
667                    return GetAddress(FromRow, FromColumn, Absolute) + ":" + GetAddress(ToRow, ToColumn, Absolute);
668                }
669            }
670        }
671        /// <summary>
672        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
673        /// </summary>
674        /// <param name="FromRow">From row number</param>
675        /// <param name="FromColumn">From column number</param>
676        /// <param name="ToRow">To row number</param>
677        /// <param name="ToColumn">From column number</param>
678        /// <param name="FixedFromColumn"></param>
679        /// <param name="FixedFromRow"></param>
680        /// <param name="FixedToColumn"></param>
681        /// <param name="FixedToRow"></param>
682        /// <returns>The cell address in the format A1</returns>
683        public static string GetAddress(int FromRow, int FromColumn, int ToRow, int ToColumn, bool FixedFromRow, bool FixedFromColumn, bool FixedToRow, bool  FixedToColumn)
684        {
685            if (FromRow == ToRow && FromColumn == ToColumn)
686            {
687                return GetAddress(FromRow, FixedFromRow, FromColumn, FixedFromColumn);
688            }
689            else
690            {
691                if (FromRow == 1 && ToRow == ExcelPackage.MaxRows)
692                {
693                    return GetColumnLetter(FromColumn, FixedFromColumn) + ":" + GetColumnLetter(ToColumn, FixedToColumn);
694                }
695                else if (FromColumn == 1 && ToColumn == ExcelPackage.MaxColumns)
696                {                   
697                    return (FixedFromRow ? "$":"") + FromRow.ToString() + ":" + (FixedToRow ? "$":"") + ToRow.ToString();
698                }
699                else
700                {
701                    return GetAddress(FromRow, FixedFromRow, FromColumn, FixedFromColumn) + ":" + GetAddress(ToRow, FixedToRow, ToColumn, FixedToColumn);
702                }
703            }
704        }
705        /// <summary>
706        /// Get the full address including the worksheet name
707        /// </summary>
708        /// <param name="worksheetName">The name of the worksheet</param>
709        /// <param name="address">The address</param>
710        /// <returns>The full address</returns>
711        public static string GetFullAddress(string worksheetName, string address)
712        {
713            return GetFullAddress(worksheetName, address, true);
714        }
715        internal static string GetFullAddress(string worksheetName, string address, bool fullRowCol)
716        {
717               if (address.IndexOf("!") == -1 || address=="#REF!")
718               {
719                   if (fullRowCol)
720                   {
721                       string[] cells = address.Split(':');
722                       if (cells.Length > 0)
723                       {
724                           address = string.Format("'{0}'!{1}", worksheetName, cells[0]);
725                           if (cells.Length > 1)
726                           {
727                               address += string.Format(":{0}", cells[1]);
728                           }
729                       }
730                   }
731                   else
732                   {
733                       var a = new ExcelAddressBase(address);
734                       if ((a._fromRow == 1 && a._toRow == ExcelPackage.MaxRows) || (a._fromCol == 1 && a._toCol == ExcelPackage.MaxColumns))
735                       {
736                           address = string.Format("'{0}'!{1}{2}:{3}{4}", worksheetName, ExcelAddress.GetColumnLetter(a._fromCol), a._fromRow, ExcelAddress.GetColumnLetter(a._toCol), a._toRow);
737                       }
738                       else
739                       {
740                           address=GetFullAddress(worksheetName, address, true);
741                       }
742                   }
743               }
744               return address;
745        }
746        #endregion
747        #region IsValidCellAddress
748        public static bool IsValidAddress(string address)
749        {
750            address = address.ToUpper(CultureInfo.InvariantCulture);
751            string r1 = "", c1 = "", r2 = "", c2 = "";
752            bool isSecond = false;
753            for (int i = 0; i < address.Length; i++)
754            {
755                if (address[i] >= 'A' && address[i] <= 'Z')
756                {
757                    if (isSecond == false)
758                    {
759                        if (r1 != "") return false;
760                        c1 += address[i];
761                        if (c1.Length > 3) return false;
762                    }
763                    else
764                    {
765                        if (r2 != "") return false;
766                        c2 += address[i];
767                        if (c2.Length > 3) return false;
768                    }
769                }
770                else if (address[i] >= '0' && address[i] <= '9')
771                {
772                    if (isSecond == false)
773                    {
774                        r1 += address[i];
775                        if (r1.Length > 7) return false;
776                    }
777                    else
778                    {
779                        r2 += address[i];
780                        if (r2.Length > 7) return false;
781                    }
782                }
783                else if (address[i] == ':')
784                {
785                    isSecond=true;
786                }
787                else if (address[i] == '$')
788                {
789                    if (i == address.Length - 1 || address[i + 1] == ':')
790                    {
791                        return false;
792                    }
793                }
794                else
795                {
796                    return false;
797                }
798            }
799
800            if (r1!="" && c1!="" && r2 == "" && c2 == "")   //Single Cell
801            {
802                return (GetColumn(c1)<=ExcelPackage.MaxColumns && int.Parse(r1)<=ExcelPackage.MaxRows);   
803            }
804            else if (r1 != "" && r2 != "" && c1 != "" && c2 != "") //Range
805            {
806                var iR2 = int.Parse(r2);
807                var iC2 = GetColumn(c2);
808
809                return GetColumn(c1) <= iC2 && int.Parse(r1) <= iR2 &&
810                    iC2 <= ExcelPackage.MaxColumns && iR2 <= ExcelPackage.MaxRows;
811                                                   
812            }
813            else if (r1 == "" && r2 == "" && c1 != "" && c2 != "") //Full Column
814            {               
815                var c2n=GetColumn(c2);
816                return (GetColumn(c1) <= c2n && c2n <= ExcelPackage.MaxColumns);
817            }
818            else if (r1 != "" && r2 != "" && c1 == "" && c2 == "")
819            {
820                var iR2 = int.Parse(r2);
821
822                return int.Parse(r1) <= iR2 && iR2 <= ExcelPackage.MaxRows;
823            }
824            else
825            {
826                return false;
827            }
828        }
829        /// <summary>
830        /// Checks that a cell address (e.g. A5) is valid.
831        /// </summary>
832        /// <param name="cellAddress">The alphanumeric cell address</param>
833        /// <returns>True if the cell address is valid</returns>
834        public static bool IsValidCellAddress(string cellAddress)
835        {
836            bool result = false;
837            try
838            {
839                int row, col;
840                if (GetRowColFromAddress(cellAddress, out row, out col))
841                {
842                    if (row > 0 && col > 0 && row <= ExcelPackage.MaxRows && col <= ExcelPackage.MaxColumns)
843                        result = true;
844                    else
845                        result = false;
846                }
847            }
848            catch { }
849            return result;
850        }
851        #endregion
852        #region UpdateFormulaReferences
853        /// <summary>
854        /// Updates the Excel formula so that all the cellAddresses are incremented by the row and column increments
855        /// if they fall after the afterRow and afterColumn.
856        /// Supports inserting rows and columns into existing templates.
857        /// </summary>
858        /// <param name="Formula">The Excel formula</param>
859        /// <param name="rowIncrement">The amount to increment the cell reference by</param>
860        /// <param name="colIncrement">The amount to increment the cell reference by</param>
861        /// <param name="afterRow">Only change rows after this row</param>
862        /// <param name="afterColumn">Only change columns after this column</param>
863        /// <returns></returns>
864        internal static string UpdateFormulaReferences(string Formula, int rowIncrement, int colIncrement, int afterRow, int afterColumn, bool setFixed=false)
865        {
866            //return Translate(Formula, AddToRowColumnTranslator, afterRow, afterColumn, rowIncrement, colIncrement);
867            var d=new Dictionary<string, object>();
868            try
869            {
870                var sct = new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty);
871                var tokens = sct.Tokenize(Formula);
872                String f = "";
873                foreach (var t in tokens)
874                {
875                    if (t.TokenType == TokenType.ExcelAddress)
876                    {
877                        var a = new ExcelAddressBase(t.Value);                       
878                        if (rowIncrement > 0)
879                        {
880                            a = a.AddRow(afterRow, rowIncrement, setFixed);
881                        }
882                        else if (rowIncrement < 0)
883                        {
884                            a = a.DeleteRow(afterRow, -rowIncrement, setFixed);
885                        }
886                        if (colIncrement > 0)
887                        {
888                            a = a.AddColumn(afterColumn, colIncrement, setFixed);
889                        }
890                        else if (colIncrement < 0)
891                        {
892                            a = a.DeleteColumn(afterColumn, -colIncrement, setFixed);
893                        }
894                        if (a == null || !a.IsValidRowCol())
895                        {
896                            f += "#REF!";
897                        }
898                        else
899                        {
900                            f += a.Address;
901                        }
902
903
904                    }
905                    else
906                    {
907                        f += t.Value;
908                    }
909                }
910                return f;
911            }
912            catch //Invalid formula, skip updateing addresses
913            {
914                return Formula;
915            }
916        }
917
918        #endregion
919        #endregion
920        #endregion
921    }
922}
Note: See TracBrowser for help on using the repository browser.