Calculator.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Collections;
  5. using Biff8Excel.Interfaces;
  6. using Biff8Excel.Excel;
  7. namespace Biff8Excel.Formulas
  8. {
  9. public class Calculator
  10. {
  11. //Calculate
  12. double[] arrStack = new double[100];
  13. ushort stackPointer;
  14. //ExcelCellLink m_cells;
  15. ExcelCellDictionary m_cells;
  16. IExternSheet m_externSheet;
  17. ushort m_thisSheetNumber;
  18. public Calculator()
  19. {
  20. //stackPointer = 0;
  21. }
  22. // If there are no sheets in the function string, use
  23. // this value to make sure we only reference cells from the formulas sheet
  24. internal ushort ThisSheetNumber
  25. {
  26. set { m_thisSheetNumber = value; }
  27. }
  28. internal IExternSheet ExternSheet
  29. {
  30. set { m_externSheet = value; }
  31. }
  32. internal ExcelCellDictionary CellCollection
  33. //internal ExcelCellLink CellCollection
  34. {
  35. set { m_cells = value; }
  36. }
  37. /// <summary>
  38. /// Procedure : Function EvaluteSupportedFunction
  39. /// </summary>
  40. /// <param name="funcString"></param>
  41. /// <returns></returns>
  42. private double EvaluteSupportedFunction(string funcString)
  43. {
  44. switch ( Globals.GetFunctionName(funcString))
  45. {
  46. case "SUM":
  47. return EvaluateSum(funcString);
  48. case "AVERAGE":
  49. return EvaluateAverage(funcString);
  50. case "COUNT":
  51. return EvaluateCount(funcString);
  52. default:
  53. return 0;
  54. }
  55. }
  56. private ushort GetSheetNumberFromName(string sheetName)
  57. {
  58. try
  59. {
  60. for (ushort i = 0; i < Globals.g_arrSheetNames.Length; i++)
  61. {
  62. if (Globals.g_arrSheetNames[i] == sheetName)
  63. return i;
  64. }
  65. throw new Biff8ExcelException("not find sheetName");
  66. }
  67. catch
  68. {
  69. throw;
  70. }
  71. }
  72. private ushort[] GetSheetRange(string funcString)
  73. {
  74. int pos;
  75. string reference;
  76. ushort first;
  77. ushort last;
  78. ushort[] result;
  79. string sheets;
  80. string sheet1;
  81. string sheet2;
  82. result = new ushort[2];
  83. reference = funcString;
  84. pos = reference.IndexOf("(");
  85. if (pos > -1)
  86. {
  87. //得到括号内的内容
  88. reference = reference.Substring(pos + 1, reference.Length - pos - 2);
  89. }
  90. // check for sheet references
  91. pos = reference.IndexOf("!");
  92. if (pos > -1)
  93. {
  94. sheets = reference.Substring(0, pos);
  95. //how many sheets are their
  96. pos = sheets.IndexOf(":");
  97. if (pos < 0)
  98. {
  99. last = first = GetSheetNumberFromName(sheets);
  100. }
  101. else
  102. {
  103. sheet1 = sheets.Substring(0, pos);
  104. if (sheets.Substring(pos + 1) == "$")
  105. sheet2 = sheets.Substring(pos + 2);
  106. else
  107. sheet2 = sheets.Substring(pos + 1);
  108. first = GetSheetNumberFromName(sheet1);
  109. last = GetSheetNumberFromName(sheet2);
  110. }
  111. result[0] = first;
  112. result[1] = last;
  113. }
  114. else
  115. {
  116. result[0] = m_thisSheetNumber;
  117. result[1] = m_thisSheetNumber;
  118. }
  119. // order the sheets 小的数在前
  120. if (result[0] > result[1])
  121. result[0] = (ushort)(result[1] + (result[1] = result[0]) * 0);
  122. return result;
  123. }
  124. //private bool IsAlphaNumeric(byte b)
  125. //{
  126. // if ((b >= 48 && b <= 57) || (b >= 65 && b <= 90) || (b >= 97 && b <= 123))
  127. // return true;
  128. // return false;
  129. //}
  130. private string GetAreaRef(string funcString)
  131. {
  132. //string area = "";
  133. StringBuilder area = new StringBuilder();
  134. int pos;
  135. //remove any Sheet references
  136. pos = funcString.IndexOf("!");
  137. if (pos > -1)
  138. {
  139. funcString = funcString.Substring(pos + 1);
  140. if (funcString.Substring(funcString.Length - 1) == ")")
  141. {
  142. funcString = funcString.Substring(0, funcString.Length - 1);
  143. return funcString;
  144. }
  145. }
  146. // Get the Cell references
  147. pos = funcString.IndexOf(":");
  148. if (pos < 0) return "";
  149. // get the left cell ref
  150. for (int i = (pos - 1); i >= 0; i--)
  151. {
  152. if (char.IsLetterOrDigit(funcString, i) && (funcString.Substring(i, 1) != "!"))
  153. //if (IsAlphaNumeric((byte)(funcString.Substring(i, 1).ToCharArray()[0])) && (funcString.Substring(i, 1) != "!"))
  154. area.Append(funcString.Substring(i, 1));
  155. else
  156. break;
  157. }
  158. string st = Globals.StrReverse(area.ToString()) + ":";
  159. area = new StringBuilder();
  160. area.Append(st);
  161. //area = Globals.StrReverse(area) + ":";
  162. // get the right cell ref
  163. for (int i = (pos + 1); i < funcString.Length; i++)
  164. {
  165. if (char.IsLetterOrDigit(funcString, i))
  166. //if (IsAlphaNumeric((byte)(funcString.Substring(i, 1).ToCharArray()[0])))
  167. area.Append( funcString.Substring(i, 1));
  168. else
  169. break;
  170. }
  171. return area.ToString() ;
  172. }
  173. private string[] GetCellReferences(string area)
  174. {
  175. string[] result;
  176. string first;
  177. string last;
  178. int count = 0;
  179. ushort rowfrom;
  180. ushort rowto;
  181. ushort colfrom;
  182. ushort colto;
  183. // get the first an last cell in the range
  184. count = area.IndexOf(":");
  185. first = area.Substring(0, count);
  186. last = area.Substring(count + 1);
  187. rowfrom = (ushort)Globals.ConvertRowStringToNum(first);
  188. colfrom = (ushort)Globals.ConvertColStringToNum(first);
  189. rowto = (ushort)Globals.ConvertRowStringToNum(last);
  190. colto = (ushort)Globals.ConvertColStringToNum(last);
  191. int num;
  192. num = (rowto - rowfrom + 1) * (colto - colfrom + 1);
  193. result = new string[num];
  194. count = 0;
  195. for (ushort x = rowfrom; x <= rowto; x++)
  196. {
  197. for (ushort y = colfrom; y <= colto; y++)
  198. {
  199. result[count] = Globals.CellReferenceFromRowColumn(x, y);
  200. count++;
  201. }
  202. }
  203. return result;
  204. }
  205. private double EvaluateSum(string funcString)
  206. {
  207. ushort count = 0 ;
  208. return EvaluateSum(funcString,ref count);
  209. }
  210. private double EvaluateSum(string funcString ,ref ushort cellEvaluated)
  211. {
  212. string area;
  213. ushort[] sheets;
  214. string[] cells;
  215. double num;
  216. double result = 0;
  217. ICell cell = null;
  218. string key;
  219. try
  220. {
  221. if (funcString.IndexOf("(") < 0) return default(double);
  222. // returns the Sheet Range (eg =Sum(Sheet1:Sheet3!A1:B1) returns 1, 2 & 3)
  223. sheets = GetSheetRange(funcString);
  224. // get the cells contained between the brackets ( format = Sum(A1:A3) returns A1:A3 )
  225. area = GetAreaRef(funcString);
  226. // get an array of all the cells in the enclosed area;
  227. cells = GetCellReferences(area);
  228. for (ushort y = sheets[0]; y <= sheets[1]; y++)
  229. {
  230. for (ushort x = 0; x < cells.Length; x++)
  231. {
  232. key = y.ToString("000") + "!" + cells[x];
  233. cell = m_cells[key];
  234. if (cell != null)
  235. {
  236. if (cell.ResolvedValue == null)
  237. result += 0;
  238. // check for a valid value in the cell
  239. else if (double.TryParse(cell.ResolvedValue.ToString(),out num) == true)
  240. result += num;
  241. cellEvaluated++;
  242. }
  243. } //end for x
  244. } // end for y
  245. return result;
  246. }
  247. catch
  248. {
  249. return default(double);
  250. }
  251. }
  252. private double EvaluateAverage(string funcString)
  253. {
  254. ushort count = 0;
  255. double sum;
  256. try
  257. {
  258. // count returns the number of cell evaluated
  259. sum = EvaluateSum(funcString,ref count);
  260. return sum / count;
  261. }
  262. catch
  263. {
  264. return default(double);
  265. }
  266. }
  267. private ushort EvaluateCount(string funcString)
  268. {
  269. try
  270. {
  271. ushort count = 0;
  272. // count returns the number of cell evaluated
  273. EvaluateSum(funcString,ref count);
  274. return count;
  275. }
  276. catch
  277. {
  278. return default(ushort);
  279. }
  280. }
  281. internal double Calculate(List<string> tokens)
  282. {
  283. int y;
  284. double num;
  285. ICell cell;
  286. string token;
  287. double lOp, rOp;
  288. string key;
  289. int pos;
  290. ushort iSheet;
  291. string sheets = "";
  292. string s;
  293. for (int i = 0; i < tokens.Count; i++)
  294. {
  295. token = tokens[i].ToString();
  296. switch (token)
  297. {
  298. case "+":
  299. rOp = arrStack[stackPointer];
  300. stackPointer--;
  301. lOp = arrStack[stackPointer];
  302. arrStack[stackPointer] = lOp + rOp;
  303. break;
  304. case "-":
  305. rOp = arrStack[stackPointer];
  306. stackPointer--;
  307. lOp = arrStack[stackPointer];
  308. arrStack[stackPointer] = lOp - rOp;
  309. break;
  310. case "*":
  311. rOp = arrStack[stackPointer];
  312. stackPointer--;
  313. lOp = arrStack[stackPointer];
  314. arrStack[stackPointer] = lOp * rOp;
  315. break;
  316. case "/":
  317. rOp = arrStack[stackPointer];
  318. stackPointer--;
  319. lOp = arrStack[stackPointer];
  320. arrStack[stackPointer] = lOp / rOp;
  321. break;
  322. case "^":
  323. rOp = arrStack[stackPointer];
  324. stackPointer--;
  325. lOp = arrStack[stackPointer];
  326. arrStack[stackPointer] = Math.Pow(lOp, rOp);
  327. break;
  328. case " ":
  329. case "":
  330. break;
  331. default:
  332. double tmp;
  333. if (double.TryParse(token, out tmp))
  334. {
  335. stackPointer++;
  336. arrStack[stackPointer] = tmp;
  337. }
  338. else if (Globals.g_sSupported.IndexOf(Globals.GetFunctionName(token)) > -1) //Supported Function
  339. {
  340. num = EvaluteSupportedFunction(token);
  341. if (default(double) != num)
  342. {
  343. stackPointer++;
  344. arrStack[stackPointer] = num;
  345. }
  346. else
  347. {
  348. return default(double);
  349. }
  350. }
  351. else
  352. {
  353. // if there is a sheet reference then get it's number
  354. // otherwise use m_thisSheetNumber
  355. pos = token.IndexOf("!");
  356. if (pos > -1)
  357. {
  358. // split out the sheet(s)
  359. y = pos - 1;
  360. do
  361. {
  362. s = token.Substring(y, 1);
  363. if ((s == "(") || (s == "$") || (s == ":")) break;
  364. sheets += s;
  365. y--;
  366. } while (y > 0);
  367. iSheet = GetSheetNumberFromName(Globals.StrReverse(sheets));
  368. s = token.Substring(pos + 1);
  369. }
  370. else
  371. {
  372. iSheet = m_thisSheetNumber;
  373. s = token;
  374. }
  375. key = iSheet.ToString("000") + "!" + s;
  376. cell = m_cells[key];
  377. if (cell == null)
  378. {
  379. stackPointer++;
  380. arrStack[stackPointer] = 0.00;
  381. }
  382. else
  383. {
  384. if (double.TryParse( cell.ResolvedValue.ToString(),out num) == true)
  385. {
  386. stackPointer++;
  387. arrStack[stackPointer] = num;
  388. }
  389. else
  390. {
  391. return default(double);
  392. }
  393. }
  394. }
  395. break;
  396. }
  397. }
  398. return arrStack[1];
  399. }
  400. }
  401. }