Improve formula conversion.
diff --git a/EPPlus/ExcelCellBase.cs b/EPPlus/ExcelCellBase.cs
index 61f8b5f..05c3fa6 100644
--- a/EPPlus/ExcelCellBase.cs
+++ b/EPPlus/ExcelCellBase.cs
@@ -86,6 +86,19 @@
{
return Translate(value, ToAbs, row, col, -1, -1);
}
+
+ /// <summary>
+ /// Translates a R1C1 to an absolut address/Formula: Version 1
+ /// </summary>
+ /// <param name="value">Address</param>
+ /// <param name="row">Current row</param>
+ /// <param name="col">Current column</param>
+ /// <returns>The RC address</returns>
+ public static string TranslateFromR1C1_V1(string value, int row, int col)
+ {
+ return Translate_V1(value, ToAbs_V1, row, col, -1, -1);
+ }
+
/// <summary>
/// Translates a absolut address to R1C1 Format
/// </summary>
@@ -97,8 +110,21 @@
{
return Translate(value, ToR1C1, row, col, -1, -1);
}
+
/// <summary>
- /// Translates betweein R1C1 or absolut addresses
+ /// Translates a absolute address to R1C1 Format : Version 1
+ /// </summary>
+ /// <param name="value">R1C1 Address</param>
+ /// <param name="row">Current row</param>
+ /// <param name="col">Current column</param>
+ /// <returns>The absolut address/Formula</returns>
+ public static string TranslateToR1C1_V1(string value, int row, int col)
+ {
+ return Translate_V1(value, ToR1C1_V1, row, col, -1, -1);
+ }
+
+ /// <summary>
+ /// Translates betweein R1C1 or absolute addresses : Version 1
/// </summary>
/// <param name="value">The addresss/function</param>
/// <param name="addressTranslator">The translating function</param>
@@ -140,6 +166,63 @@
{
ret += c;
}
+ else
+ {
+ if ((c == '-' || c == '+' || c == '*' || c == '/' ||
+ c == '=' || c == '^' || c == ',' || c == ':' ||
+ c == '<' || c == '>' || c == '(' || c == ')' || c == '!' ||
+ c == ' ' || c == '&' || c == '%') &&
+ (pos == 0 || value[pos - 1] != '[')) //Last part to allow for R1C1 style [-x]
+ {
+ ret += addressTranslator(part, row, col, rowIncr, colIncr) + c;
+ part = "";
+ }
+ else
+ {
+ part += c;
+ }
+ }
+ }
+ if (part != "")
+ {
+ ret += addressTranslator(part, row, col, rowIncr, colIncr);
+ }
+ return ret;
+ }
+
+ private static string Translate_V1(string value, dlgTransl addressTranslator, int row, int col, int rowIncr, int colIncr)
+ {
+ if (value == "")
+ return "";
+ bool isText = false;
+ string ret = "";
+ string part = "";
+ char prevTQ = (char)0;
+ for (int pos = 0; pos < value.Length; pos++)
+ {
+ char c = value[pos];
+ if (c == '"' || c == '\'')
+ {
+ if (isText == true && prevTQ != c)
+ {
+ ret += c;
+ continue;
+ }
+
+ if (isText == false && part != "" && prevTQ == c)
+ {
+ ret += addressTranslator(part, row, col, rowIncr, colIncr);
+ part = "";
+ prevTQ = (char)0;
+ }
+ prevTQ = c;
+ isText = !isText;
+ ret += c;
+ }
+ else if (isText)
+ {
+ ret += c;
+ }
else if (c == ':') // Keep Range expressions together
{
part += c;
@@ -167,6 +250,7 @@
}
return ret;
}
+
/// <summary>
/// Translate to R1C1
/// </summary>
@@ -179,11 +263,49 @@
private static string ToR1C1(string part, int row, int col, int rowIncr, int colIncr)
{
int addrRow, addrCol;
+ string Ret = "R";
+ if (GetRowCol(part, out addrRow, out addrCol, false))
+ {
+ if (addrRow == 0 || addrCol == 0)
+ {
+ return part;
+ }
+ if (part.IndexOf('$', 1) > 0)
+ {
+ Ret += addrRow.ToString();
+ }
+ else if (addrRow - row != 0)
+ {
+ Ret += string.Format("[{0}]", addrRow - row);
+ }
+
+ if (part.StartsWith("$"))
+ {
+ return Ret + "C" + addrCol;
+ }
+ else if (addrCol - col != 0)
+ {
+ return Ret + "C" + string.Format("[{0}]", addrCol - col);
+ }
+ else
+ {
+ return Ret + "C";
+ }
+ }
+ else
+ {
+ return part;
+ }
+ }
+
+ private static string ToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr)
+ {
+ int addrRow, addrCol;
// Handle range expressions
if ((part.Length > 1) && (part.IndexOf(':', 1) > 0))
{
- return RangeToR1C1(part, row, col, rowIncr, colIncr);
+ return RangeToR1C1_V1(part, row, col, rowIncr, colIncr);
}
string Ret = "R";
@@ -221,28 +343,28 @@
}
}
- private static string RangeToR1C1(string part, int row, int col, int rowIncr, int colIncr)
+ private static string RangeToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr)
{
// Split range expression
string[] cellValues = part.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
// Convert range expressions
string result = "";
- result += RangeCellToR1C1(cellValues[0], row, col, rowIncr, colIncr);
+ result += RangeCellToR1C1_V1(cellValues[0], row, col, rowIncr, colIncr);
result += ":";
- result += RangeCellToR1C1(cellValues[1], row, col, rowIncr, colIncr);
+ result += RangeCellToR1C1_V1(cellValues[1], row, col, rowIncr, colIncr);
// Return converted range expression
return result;
}
- private static string RangeCellToR1C1(string part, int row, int col, int rowIncr, int colIncr)
+ private static string RangeCellToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr)
{
int addrRow, addrCol;
bool fixedRow, fixedCol;
string result = "";
- if (GetRowCol(part, out addrRow, out addrCol, false, out fixedRow, out fixedCol))
+ if (GetRowCol_V1(part, out addrRow, out addrCol, false, out fixedRow, out fixedCol))
{
if (addrRow > 0)
{
@@ -291,9 +413,50 @@
/// <returns></returns>
///
-
+
private static string ToAbs(string part, int row, int col, int rowIncr, int colIncr)
{
+ string check = part.ToUpper(CultureInfo.InvariantCulture);
+
+ int rStart = check.IndexOf("R");
+ if (rStart != 0)
+ return part;
+ if (part.Length == 1) //R
+ {
+ return GetAddress(row, col);
+ }
+
+ int cStart = check.IndexOf("C");
+ bool absoluteRow, absoluteCol;
+ if (cStart == -1)
+ {
+ int RNum = GetRC(part, row, out absoluteRow);
+ if (RNum > int.MinValue)
+ {
+ return GetAddress(RNum, absoluteRow, col, false);
+ }
+ else
+ {
+ return part;
+ }
+ }
+ else
+ {
+ int RNum = GetRC(part.Substring(1, cStart - 1), row, out absoluteRow);
+ int CNum = GetRC(part.Substring(cStart + 1, part.Length - cStart - 1), col, out absoluteCol);
+ if (RNum > int.MinValue && CNum > int.MinValue)
+ {
+ return GetAddress(RNum, absoluteRow, CNum, absoluteCol);
+ }
+ else
+ {
+ return part;
+ }
+ }
+ }
+
+ private static string ToAbs_V1(string part, int row, int col, int rowIncr, int colIncr)
+ {
bool absoluteCol = false;
bool absoluteRow = false;
int colNum = -1;
@@ -306,7 +469,7 @@
// Handle range expressions
if ((part.Length > 1) && (part.IndexOf(':', 1) > 0))
{
- return RangeToA1(part, row, col, rowIncr, colIncr);
+ return RangeToA1_V1(part, row, col, rowIncr, colIncr);
}
// Ensure part is present
@@ -337,7 +500,7 @@
{
// "R" followed by relative row number
pos += 1;
- num = GetNumber(check.Substring(pos, part.Length - pos), out numLength);
+ num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
if (num == Int32.MinValue)
return part;
pos += numLength;
@@ -358,7 +521,7 @@
else if (pos < part.Length)
{
// "R" followed by absolute row number
- num = GetNumber(check.Substring(pos, part.Length - pos), out numLength);
+ num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
if (rowNum == Int32.MinValue)
return part;
pos += numLength;
@@ -383,7 +546,7 @@
{
// "C" followed by relative column number
pos += 1;
- num = GetNumber(check.Substring(pos, part.Length - pos), out numLength);
+ num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
if (num == Int32.MinValue)
return part;
pos += numLength;
@@ -404,7 +567,7 @@
else if (pos < part.Length)
{
// "C" followed by absolute column number
- num = GetNumber(check.Substring(pos, part.Length - pos), out numLength);
+ num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
if (num == Int32.MinValue)
return part;
pos += numLength;
@@ -443,7 +606,7 @@
return result;
}
- private static int GetNumber(string value, out int length)
+ private static int GetNumber_V1(string value, out int length)
{
// Get number length
length = 0;
@@ -473,28 +636,28 @@
return (int.TryParse(value.Substring(0, length), out result)) ? result : Int32.MinValue;
}
- private static string RangeToA1(string part, int row, int col, int rowIncr, int colIncr)
+ private static string RangeToA1_V1(string part, int row, int col, int rowIncr, int colIncr)
{
// Split range expression
string[] cellValues = part.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
// Convert range expressions
string result = "";
- result += ToAbs(cellValues[0], row, col, rowIncr, colIncr);
+ result += ToAbs_V1(cellValues[0], row, col, rowIncr, colIncr);
result += ":";
- result += ToAbs(cellValues[1], row, col, rowIncr, colIncr);
+ result += ToAbs_V1(cellValues[1], row, col, rowIncr, colIncr);
// Return converted range expression
return result;
}
- private static string RangeCellToA1(string part, int row, int col, int rowIncr, int colIncr)
+ private static string RangeCellToA1_V1(string part, int row, int col, int rowIncr, int colIncr)
{
int addrRow, addrCol;
bool fixedRow, fixedCol;
string result = "";
- if (GetRowCol(part, out addrRow, out addrCol, false, out fixedRow, out fixedCol))
+ if (GetRowCol_V1(part, out addrRow, out addrCol, false, out fixedRow, out fixedCol))
{
if (addrRow > 0)
{
@@ -596,8 +759,44 @@
/// <param name="OffsetValue"></param>
/// <param name="fixedAddr"></param>
/// <returns></returns>
+ ///
private static int GetRC(string value, int OffsetValue, out bool fixedAddr)
{
+ if (value == "")
+ {
+ fixedAddr = false;
+ return OffsetValue;
+ }
+ int num;
+ if (value[0] == '[' && value[value.Length - 1] == ']') //Offset?
+ {
+ fixedAddr = false;
+ if (int.TryParse(value.Substring(1, value.Length - 2), out num))
+ {
+ return (OffsetValue + num);
+ }
+ else
+ {
+ return int.MinValue;
+ }
+ }
+ else
+ {
+ // Absolute address
+ fixedAddr = true;
+ if (int.TryParse(value, out num))
+ {
+ return num;
+ }
+ else
+ {
+ return int.MinValue;
+ }
+ }
+ }
+
+ private static int GetRC_V1(string value, int OffsetValue, out bool fixedAddr)
+ {
if ((value == "") || (value == "R") || (value == "C"))
{
// Relative address with no offset
@@ -767,7 +966,6 @@
internal static bool GetRowCol(string address, out int row, out int col, bool throwException, out bool fixedRow, out bool fixedCol)
{
bool colPart = true;
- bool isFixed = false;
int colStartIx = 0;
int colLength = 0;
col = 0;
@@ -791,54 +989,123 @@
for (int i = colStartIx; i < address.Length; i++)
{
char c = address[i];
- if (c == '$')
+ if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3)
{
- // Absolute address
- isFixed = true;
- }
- else if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3)
- {
- // Column portion of address
- if (isFixed)
- {
- fixedCol = true;
- isFixed = false;
- }
-
- col *= 26;
- col += ((int)c) - 64;
- colLength++;
+ col *= 26;
+ col += ((int)c) - 64;
+ colLength++;
}
else if (c >= '0' && c <= '9')
{
- // Row portion of address
- if (isFixed)
- {
- fixedRow = true;
- isFixed = false;
- }
-
- row *= 10;
- row += ((int)c) - 48;
- colPart = false;
+ row *= 10;
+ row += ((int)c) - 48;
+ colPart = false;
+ }
+ else if (c == '$')
+ {
+ if (i == colStartIx)
+ {
+ colStartIx++;
+ fixedCol = true;
+ }
+ else
+ {
+ colPart = false;
+ fixedRow = true;
+ }
}
else
{
- row = 0;
- col = 0;
- if (throwException)
- {
- throw (new Exception(string.Format("Invalid Address format {0}", address)));
- }
- else
- {
- return false;
- }
+ row = 0;
+ col = 0;
+ if (throwException)
+ {
+ throw (new Exception(string.Format("Invalid Address format {0}", address)));
+ }
+ else
+ {
+ return false;
+ }
}
}
return row != 0 || col != 0;
}
+ internal static bool GetRowCol_V1(string address, out int row, out int col, bool throwException, out bool fixedRow, out bool fixedCol)
+ {
+ bool colPart = true;
+ bool isFixed = false;
+ int colStartIx = 0;
+ int colLength = 0;
+ col = 0;
+ row = 0;
+ fixedRow = false;
+ fixedCol = false;
+
+ if (address.EndsWith("#REF!"))
+ {
+ row = 0;
+ col = 0;
+ return true;
+ }
+
+ int sheetMarkerIndex = address.IndexOf('!');
+ if (sheetMarkerIndex >= 0)
+ {
+ colStartIx = sheetMarkerIndex + 1;
+ }
+ address = address.ToUpper(CultureInfo.InvariantCulture);
+ for (int i = colStartIx; i < address.Length; i++)
+ {
+ char c = address[i];
+ if (c == '$')
+ {
+ // Absolute address
+ isFixed = true;
+ }
+ else if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3)
+ {
+ // Column portion of address
+ if (isFixed)
+ {
+ fixedCol = true;
+ isFixed = false;
+ }
+
+ col *= 26;
+ col += ((int)c) - 64;
+ colLength++;
+ }
+ else if (c >= '0' && c <= '9')
+ {
+ // Row portion of address
+ if (isFixed)
+ {
+ fixedRow = true;
+ isFixed = false;
+ }
+
+ row *= 10;
+ row += ((int)c) - 48;
+ colPart = false;
+ }
+ else
+ {
+ row = 0;
+ col = 0;
+ if (throwException)
+ {
+ throw (new Exception(string.Format("Invalid Address format {0}", address)));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ return row != 0 || col != 0;
+ }
+
private static int GetColumn(string sCol)
{
int col = 0;
@@ -1134,6 +1401,8 @@
/// <returns></returns>
internal static string UpdateFormulaReferences(string Formula, int rowIncrement, int colIncrement, int afterRow, int afterColumn, bool setFixed=false)
{
+ return "";
+ /*
//return Translate(Formula, AddToRowColumnTranslator, afterRow, afterColumn, rowIncrement, colIncrement);
var d=new Dictionary<string, object>();
try
@@ -1192,6 +1461,7 @@
{
return Formula;
}
+ */
}
#endregion