Free cookie consent management tool by TermsFeed Policy Generator

source: branches/WebJobManager/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/ExcelCellBase.cs

Last change on this file was 12101, checked in by sraggl, 10 years ago

#2341: Fixed Bug Validate fails after exception is thrown if address is invalid

File size: 35.9 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            bool colPart = true;
485            int colStartIx = 0;
486            int colLength = 0;
487            col = 0;
488            row = 0;
489            fixedRow = false;
490            fixedCol = false;
491
492            if (address.EndsWith("#REF!"))
493            {
494                row = 0;
495                col = 0;
496                return true;
497            }
498
499            int sheetMarkerIndex = address.IndexOf('!');
500            if (sheetMarkerIndex >= 0)
501            {
502                colStartIx = sheetMarkerIndex + 1;
503            }
504
505            for (int i = colStartIx; i < address.Length; i++)
506            {
507                char c = address[i];
508                if (colPart && ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) && colLength <= 3)
509                {
510                    col *= 26;
511                    col += ((int)c) - 64;
512                    colLength++;
513                }
514                else if (c >= '0' && c <= '9')
515                {
516                    row *= 10;
517                    row += ((int)c) - 48;
518                    colPart = false;
519                }
520                else if (c == '$')
521                {
522                    if (i == colStartIx)
523                    {
524                        colStartIx++;
525                        fixedCol = true;
526                    }
527                    else
528                    {
529                        colPart = false;
530                        fixedRow = true;
531                    }
532                }
533                else if (c == ':')
534                {
535                    break;
536                }
537                else
538                {
539                    row = 0;
540                    col = 0;
541                    if (throwException)
542                    {
543                        throw (new Exception(string.Format("Invalid Address format {0}", address)));
544                    }
545                    else
546                    {
547                        return false;
548                    }
549                }
550            }
551            return row != 0 || col != 0;
552        }
553
554        private static int GetColumn(string sCol)
555        {
556            int col = 0;
557            int len = sCol.Length - 1;
558            for (int i = len; i >= 0; i--)
559            {
560                col += (((int)sCol[i]) - 64) * (int)(Math.Pow(26, len - i));
561            }
562            return col;
563        }
564        #region GetAddress
565        /// <summary>
566        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
567        /// </summary>
568        /// <param name="Row">The number of the row</param>
569        /// <param name="Column">The number of the column in the worksheet</param>
570        /// <returns>The cell address in the format A1</returns>
571        public static string GetAddress(int Row, int Column)
572        {
573            return GetAddress(Row, Column,false);
574        }
575        /// <summary>
576        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
577        /// </summary>
578        /// <param name="Row">The number of the row</param>
579        /// <param name="Column">The number of the column in the worksheet</param>
580        /// <param name="AbsoluteRow">Absolute row</param>
581        /// <param name="AbsoluteCol">Absolute column</param>
582        /// <returns>The cell address in the format A1</returns>
583        public static string GetAddress(int Row, bool AbsoluteRow, int Column, bool AbsoluteCol)
584        {
585            return ( AbsoluteCol ? "$" : "") + GetColumnLetter(Column) + ( AbsoluteRow ? "$" : "") + Row.ToString();
586        }
587        /// <summary>
588        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
589        /// </summary>
590        /// <param name="Row">The number of the row</param>
591        /// <param name="Column">The number of the column in the worksheet</param>
592        /// <param name="Absolute">Get an absolute address ($A$1)</param>
593        /// <returns>The cell address in the format A1</returns>
594        public static string GetAddress(int Row, int Column, bool Absolute)
595        {
596            if (Row == 0 || Column == 0)
597            {
598                return "#REF!";
599            }
600            if (Absolute)
601            {
602                return ("$" + GetColumnLetter(Column) + "$" + Row.ToString());
603            }
604            else
605            {
606                return (GetColumnLetter(Column) + Row.ToString());
607            }
608        }
609        /// <summary>
610        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
611        /// </summary>
612        /// <param name="FromRow">From row number</param>
613        /// <param name="FromColumn">From column number</param>
614        /// <param name="ToRow">To row number</param>
615        /// <param name="ToColumn">From column number</param>
616        /// <returns>The cell address in the format A1</returns>
617        public static string GetAddress(int FromRow, int FromColumn, int ToRow, int ToColumn)
618        {
619            return GetAddress(FromRow, FromColumn, ToRow, ToColumn, false);
620        }
621        /// <summary>
622        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
623        /// </summary>
624        /// <param name="FromRow">From row number</param>
625        /// <param name="FromColumn">From column number</param>
626        /// <param name="ToRow">To row number</param>
627        /// <param name="ToColumn">From column number</param>
628        /// <param name="Absolute">if true address is absolute (like $A$1)</param>
629        /// <returns>The cell address in the format A1</returns>
630        public static string GetAddress(int FromRow, int FromColumn, int ToRow, int ToColumn, bool Absolute)
631        {
632            if (FromRow == ToRow && FromColumn == ToColumn)
633            {
634                return GetAddress(FromRow, FromColumn, Absolute);
635            }
636            else
637            {
638                if (FromRow == 1 && ToRow == ExcelPackage.MaxRows)
639                {
640                    var absChar = Absolute ? "$" : "";
641                    return absChar + GetColumnLetter(FromColumn) + ":" + absChar + GetColumnLetter(ToColumn);
642                }
643                else if(FromColumn==1 && ToColumn==ExcelPackage.MaxColumns)
644                {
645                    var absChar = Absolute ? "$" : "";
646                    return absChar + FromRow.ToString() + ":" + absChar + ToRow.ToString();
647                }
648                else
649                {
650                    return GetAddress(FromRow, FromColumn, Absolute) + ":" + GetAddress(ToRow, ToColumn, Absolute);
651                }
652            }
653        }
654        /// <summary>
655        /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
656        /// </summary>
657        /// <param name="FromRow">From row number</param>
658        /// <param name="FromColumn">From column number</param>
659        /// <param name="ToRow">To row number</param>
660        /// <param name="ToColumn">From column number</param>
661        /// <param name="FixedFromColumn"></param>
662        /// <param name="FixedFromRow"></param>
663        /// <param name="FixedToColumn"></param>
664        /// <param name="FixedToRow"></param>
665        /// <returns>The cell address in the format A1</returns>
666        public static string GetAddress(int FromRow, int FromColumn, int ToRow, int ToColumn, bool FixedFromRow, bool FixedFromColumn, bool FixedToRow, bool  FixedToColumn)
667        {
668            if (FromRow == ToRow && FromColumn == ToColumn)
669            {
670                return GetAddress(FromRow, FixedFromRow, FromColumn, FixedFromColumn);
671            }
672            else
673            {
674                if (FromRow == 1 && ToRow == ExcelPackage.MaxRows)
675                {
676                    return GetColumnLetter(FromColumn, FixedFromColumn) + ":" + GetColumnLetter(ToColumn, FixedToColumn);
677                }
678                else if (FromColumn == 1 && ToColumn == ExcelPackage.MaxColumns)
679                {                   
680                    return (FixedFromRow ? "$":"") + FromRow.ToString() + ":" + (FixedToRow ? "$":"") + ToRow.ToString();
681                }
682                else
683                {
684                    return GetAddress(FromRow, FixedFromRow, FromColumn, FixedFromColumn) + ":" + GetAddress(ToRow, FixedToRow, ToColumn, FixedToColumn);
685                }
686            }
687        }
688        /// <summary>
689        /// Get the full address including the worksheet name
690        /// </summary>
691        /// <param name="worksheetName">The name of the worksheet</param>
692        /// <param name="address">The address</param>
693        /// <returns>The full address</returns>
694        public static string GetFullAddress(string worksheetName, string address)
695        {
696            return GetFullAddress(worksheetName, address, true);
697        }
698        internal static string GetFullAddress(string worksheetName, string address, bool fullRowCol)
699        {
700               if (address.IndexOf("!") == -1 || address=="#REF!")
701               {
702                   if (fullRowCol)
703                   {
704                       string[] cells = address.Split(':');
705                       if (cells.Length > 0)
706                       {
707                           address = string.Format("'{0}'!{1}", worksheetName, cells[0]);
708                           if (cells.Length > 1)
709                           {
710                               address += string.Format(":{0}", cells[1]);
711                           }
712                       }
713                   }
714                   else
715                   {
716                       var a = new ExcelAddressBase(address);
717                       if ((a._fromRow == 1 && a._toRow == ExcelPackage.MaxRows) || (a._fromCol == 1 && a._toCol == ExcelPackage.MaxColumns))
718                       {
719                           address = string.Format("'{0}'!{1}{2}:{3}{4}", worksheetName, ExcelAddress.GetColumnLetter(a._fromCol), a._fromRow, ExcelAddress.GetColumnLetter(a._toCol), a._toRow);
720                       }
721                       else
722                       {
723                           address=GetFullAddress(worksheetName, address, true);
724                       }
725                   }
726               }
727               return address;
728        }
729        #endregion
730        #region IsValidCellAddress
731        public static bool IsValidAddress(string address)
732        {
733            address = address.ToUpper(CultureInfo.InvariantCulture);
734            string r1 = "", c1 = "", r2 = "", c2 = "";
735            bool isSecond = false;
736            for (int i = 0; i < address.Length; i++)
737            {
738                if (address[i] >= 'A' && address[i] <= 'Z')
739                {
740                    if (isSecond == false)
741                    {
742                        if (r1 != "") return false;
743                        c1 += address[i];
744                        if (c1.Length > 3) return false;
745                    }
746                    else
747                    {
748                        if (r2 != "") return false;
749                        c2 += address[i];
750                        if (c2.Length > 3) return false;
751                    }
752                }
753                else if (address[i] >= '0' && address[i] <= '9')
754                {
755                    if (isSecond == false)
756                    {
757                        r1 += address[i];
758                        if (r1.Length > 7) return false;
759                    }
760                    else
761                    {
762                        r2 += address[i];
763                        if (r2.Length > 7) return false;
764                    }
765                }
766                else if (address[i] == ':')
767                {
768                    isSecond=true;
769                }
770                else if (address[i] == '$')
771                {
772                    if (i == address.Length - 1 || address[i + 1] == ':')
773                    {
774                        return false;
775                    }
776                }
777                else
778                {
779                    return false;
780                }
781            }
782
783            if (r1!="" && c1!="" && r2 == "" && c2 == "")   //Single Cell
784            {
785                return (GetColumn(c1)<=ExcelPackage.MaxColumns && int.Parse(r1)<=ExcelPackage.MaxRows);   
786            }
787            else if (r1 != "" && r2 != "" && c1 != "" && c2 != "") //Range
788            {
789                var iR2 = int.Parse(r2);
790                var iC2 = GetColumn(c2);
791
792                return GetColumn(c1) <= iC2 && int.Parse(r1) <= iR2 &&
793                    iC2 <= ExcelPackage.MaxColumns && iR2 <= ExcelPackage.MaxRows;
794                                                   
795            }
796            else if (r1 == "" && r2 == "" && c1 != "" && c2 != "") //Full Column
797            {               
798                var c2n=GetColumn(c2);
799                return (GetColumn(c1) <= c2n && c2n <= ExcelPackage.MaxColumns);
800            }
801            else if (r1 != "" && r2 != "" && c1 == "" && c2 == "")
802            {
803                var iR2 = int.Parse(r2);
804
805                return int.Parse(r1) <= iR2 && iR2 <= ExcelPackage.MaxRows;
806            }
807            else
808            {
809                return false;
810            }
811        }
812        /// <summary>
813        /// Checks that a cell address (e.g. A5) is valid.
814        /// </summary>
815        /// <param name="cellAddress">The alphanumeric cell address</param>
816        /// <returns>True if the cell address is valid</returns>
817        public static bool IsValidCellAddress(string cellAddress)
818        {
819            bool result = false;
820            try
821            {
822                int row, col;
823                if (GetRowColFromAddress(cellAddress, out row, out col))
824                {
825                    if (row > 0 && col > 0 && row <= ExcelPackage.MaxRows && col <= ExcelPackage.MaxColumns)
826                        result = true;
827                    else
828                        result = false;
829                }
830            }
831            catch { }
832            return result;
833        }
834        #endregion
835        #region UpdateFormulaReferences
836        /// <summary>
837        /// Updates the Excel formula so that all the cellAddresses are incremented by the row and column increments
838        /// if they fall after the afterRow and afterColumn.
839        /// Supports inserting rows and columns into existing templates.
840        /// </summary>
841        /// <param name="Formula">The Excel formula</param>
842        /// <param name="rowIncrement">The amount to increment the cell reference by</param>
843        /// <param name="colIncrement">The amount to increment the cell reference by</param>
844        /// <param name="afterRow">Only change rows after this row</param>
845        /// <param name="afterColumn">Only change columns after this column</param>
846        /// <returns></returns>
847        internal static string UpdateFormulaReferences(string Formula, int rowIncrement, int colIncrement, int afterRow, int afterColumn, bool setFixed=false)
848        {
849            //return Translate(Formula, AddToRowColumnTranslator, afterRow, afterColumn, rowIncrement, colIncrement);
850            var d=new Dictionary<string, object>();
851            try
852            {
853                var sct = new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty);
854                var tokens = sct.Tokenize(Formula);
855                String f = "";
856                foreach (var t in tokens)
857                {
858                    if (t.TokenType == TokenType.ExcelAddress)
859                    {
860                        var a = new ExcelAddressBase(t.Value);                       
861                        if (rowIncrement > 0)
862                        {
863                            a = a.AddRow(afterRow, rowIncrement, setFixed);
864                        }
865                        else if (rowIncrement < 0)
866                        {
867                            a = a.DeleteRow(afterRow, -rowIncrement, setFixed);
868                        }
869                        if (colIncrement > 0)
870                        {
871                            a = a.AddColumn(afterColumn, colIncrement, setFixed);
872                        }
873                        else if (colIncrement < 0)
874                        {
875                            a = a.DeleteColumn(afterColumn, -colIncrement, setFixed);
876                        }
877                        if (a == null || !a.IsValidRowCol())
878                        {
879                            f += "#REF!";
880                        }
881                        else
882                        {
883                            f += a.Address;
884                        }
885
886
887                    }
888                    else
889                    {
890                        f += t.Value;
891                    }
892                }
893                return f;
894            }
895            catch //Invalid formula, skip updateing addresses
896            {
897                return Formula;
898            }
899        }
900
901        #endregion
902        #endregion
903        #endregion
904    }
905}
Note: See TracBrowser for help on using the repository browser.