blob: 802bdd49e4eeab4d6d22afa3ed7dafa55b3c45ca [file] [log] [blame]
/***************************************************************************
Copyright (c) Microsoft Corporation 2012-2015.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
Published at http://OpenXmlDeveloper.org
Resource Center and Documentation: http://openxmldeveloper.org/wiki/w/wiki/powertools-for-open-xml.aspx
Developer: Eric White
Blog: http://www.ericwhite.com
Twitter: @EricWhiteDev
Email: eric@ericwhite.com
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExcelFormula
{
public class ParseFormula
{
ExcelFormula parser;
public ParseFormula(string formula)
{
parser = new ExcelFormula(formula, Console.Out);
bool parserResult = false;
try
{
parserResult = parser.Formula();
}
catch (Peg.Base.PegException)
{
}
if (!parserResult)
{
parser.Warning("Error processing " + formula);
}
}
public string ReplaceSheetName(string oldName, string newName)
{
StringBuilder text = new StringBuilder(parser.GetSource());
ReplaceNode(parser.GetRoot(), (int)EExcelFormula.SheetName, oldName, newName, text);
return text.ToString();
}
public string ReplaceRelativeCell(int rowOffset, int colOffset)
{
StringBuilder text = new StringBuilder(parser.GetSource());
ReplaceRelativeCell(parser.GetRoot(), rowOffset, colOffset, text);
return text.ToString();
}
// Recursive function that will replace values from last to first
private void ReplaceNode(Peg.Base.PegNode node, int id, string oldName, string newName, StringBuilder text)
{
if (node.next_ != null)
ReplaceNode(node.next_, id, oldName, newName, text);
if (node.id_ == id && parser.GetSource().Substring(node.match_.posBeg_, node.match_.Length) == oldName)
{
text.Remove(node.match_.posBeg_, node.match_.Length);
text.Insert(node.match_.posBeg_, newName);
}
else if (node.child_ != null)
ReplaceNode(node.child_, id, oldName, newName, text);
}
// Recursive function that will adjust relative cells from last to first
private void ReplaceRelativeCell(Peg.Base.PegNode node, int rowOffset, int colOffset, StringBuilder text)
{
if (node.next_ != null)
ReplaceRelativeCell(node.next_, rowOffset, colOffset, text);
if (node.id_ == (int)EExcelFormula.A1Row && parser.GetSource().Substring(node.match_.posBeg_, 1) != "$")
{
int rowNumber = Convert.ToInt32(parser.GetSource().Substring(node.match_.posBeg_, node.match_.Length));
text.Remove(node.match_.posBeg_, node.match_.Length);
text.Insert(node.match_.posBeg_, Convert.ToString(rowNumber + rowOffset));
}
else if (node.id_ == (int)EExcelFormula.A1Column && parser.GetSource().Substring(node.match_.posBeg_, 1) != "$")
{
int colNumber = GetColumnNumber(parser.GetSource().Substring(node.match_.posBeg_, node.match_.Length));
text.Remove(node.match_.posBeg_, node.match_.Length);
text.Insert(node.match_.posBeg_, GetColumnId(colNumber + colOffset));
}
else if (node.child_ != null)
ReplaceRelativeCell(node.child_, rowOffset, colOffset, text);
}
// Converts the column reference string to a column number (e.g. A -> 1, B -> 2)
private static int GetColumnNumber(string cellReference)
{
int columnNumber = 0;
foreach (char c in cellReference)
{
if (Char.IsLetter(c))
columnNumber = columnNumber * 26 + System.Convert.ToInt32(c) - System.Convert.ToInt32('A') + 1;
}
return columnNumber;
}
// Translates the column number to the column reference string (e.g. 1 -> A, 2-> B)
private static string GetColumnId(int columnNumber)
{
string result = "";
do
{
result = ((char)((columnNumber - 1) % 26 + (int)'A')).ToString() + result;
columnNumber = (columnNumber - 1) / 26;
} while (columnNumber != 0);
return result;
}
}
}