哪个正则expression式能够在C#中的公式中selectexcel列名?
我正在nedding C#中实现excel公式自动填充。
假设这个公式位于B100:
=SUM($B$99:B99)
我想在C100中使这个公式不同:
=SUM($B$99:C99)
这个公式只是一个例子。 一些真实的例子是:
=(SUM($B${0}:B{0})/SUM({1}!$B${0}:{1}!B{0}) -1) =SUM(B{0}:B{1}) =B{0} + B{1} =C{0}+ B{1} =$B${0}+ AC{1}
(考虑{0}和{1}实际上是数字)
一般来说, 我需要做的是挑选这些列名并“增加”它们。 公式中$所包围的列名不应该更新。
如何用正则expression式来识别这些字段?
这是一个只处理公式的正则expression式解决scheme。 我会把Excel的东西留给你。 假设你有一个代表公式的string集合,你可以通过这个来运行它们来增加你的列名。
一些评论:
- **彻底testing!**也许手动做一个表,并比较你的努力与生成的结果。
- 这不应该意外地改变符合单元格命名模式的函数名称。 如果您知道您的公式包含数字的Excel函数名称,请留意它们,并再次validation结果**。
- 正则expression式不validation你喂养它是一个公式 – 我认为你只使用公式。 换句话说,我没有检查string是以“=”号开头的。 如果您计划通过此方法为其他单元格值提供非公式,请使用formula.StartsWith(“=”)添加一个IsMatch在if分支中的使用位置。 为了理解我指的是什么,在我的示例中添加一个额外的testingstring,例如“Check out T4 generation” – 如果没有进行StartsWith(“=”)检查,那么匹配并且T4将变成U4。
正则expression式模式实际上是简单的部分。 它将只匹配任何字母数字序列,并忽略$ A $ 1和$ A1types的单元格。 棘手的部分是增加列的逻辑。 我已经添加了评论来澄清这一点,所以抓住一些咖啡,并阅读它:)
我相信这可能会增强,但这是我的时间。
using System.Text.RegularExpressions; static void Main(string[] args) { string[] formulas = { "Z1", "ZZ1", "AZ1", "AZB1", "BZZ2", "=SUM($B$99:B99)","=SUM($F99:F99)", "=(SUM($B$0:B0)/SUM(1!$B$11:22!B33) -1)", "=SUM(X80:Z1)", "=A0 + B1 - C2 + Z5", "=C0+ B1", "=$B$0+ AC1", "=AA12-ZZ34 + AZ1 - BZ2 - BX3 + BZX4", "=SUMX2MY2(A2:A8,B2:B8)", // ensure function SUMX2MY2 isn't mistakenly incremented "=$B$40 + 50 - 20" // no match //,"Check out T4 generation!" // not a formula but it'll still increment T4, use formula.StartsWith("=") }; // use this if you don't want to include regex comments //Regex rxCell = new Regex(@"(?<![$])\b(?<col>[AZ]+)(?<row>\d+)\b"); // regex comments in this style requires RegexOptions.IgnorePatternWhitespace string rxCellPattern = @"(?<![$]) # match if prefix is absent: $ symbol (prevents matching $A1 type of cells) # (if all you have is $A$1 type of references, and not $A1 types, this negative look-behind isn't needed) \b # word boundary (prevents matching Excel functions with a similar pattern to a cell) (?<col>[AZ]+) # named capture group, match uppercase letter at least once # (change to [A-Za-z] if you have lowercase cells) (?<row>\d+) # named capture group, match a number at least once \b # word boundary "; Regex rxCell = new Regex(rxCellPattern, RegexOptions.IgnorePatternWhitespace); foreach (string formula in formulas) { if (rxCell.IsMatch(formula)) { Console.WriteLine("Formula: {0}", formula); foreach (Match cell in rxCell.Matches(formula)) Console.WriteLine("Cell: {0}, Col: {1}", cell.Value, cell.Groups["col"].Value); // the magic happens here string newFormula = rxCell.Replace(formula, IncrementColumn); Console.WriteLine("Modified: {0}", newFormula); } else { Console.WriteLine("Not a match: {0}", formula); } Console.WriteLine(); } } private static string IncrementColumn(Match m) { string col = m.Groups["col"].Value; char c; // single character column name (ie. A1) if (col.Length == 1) { c = Convert.ToChar(col); if (c == 'Z') { // roll over col = "AA"; } else { // advance to next char c = (char)((int)c + 1); col = c.ToString(); } } else { // multi-character column name (ie. AB1) // in this case work backwards to do some column name "arithmetic" c = Convert.ToChar(col.Substring(col.Length - 1, 1)); // grab last letter of col if (c == 'Z') { string temp = ""; for (int i = col.Length - 1; i >= 0; i--) { // roll over should occur if (col[i] == 'Z') { // prepend AA if current char is not the last char in column and its next neighbor was also a Z // ie. column BZZ: if current char is 1st Z, it's neighbor Z (2nd Z) just got incremented, so 1st Z becomes AA if (i != col.Length - 1 && col[i + 1] == 'Z') { temp = "AA" + temp; } else { // last char in column is Z, becomes A (this will happen first, before the above if branch ever happens) temp = "A" + temp; } } else { temp = ((char)((int)col[i] + 1)).ToString() + temp; } } col = temp; } else { // advance char c = (char)((int)c + 1); // chop off final char in original column, append advanced char col = col.Remove(col.Length - 1) + c.ToString(); } } // updated column and original row (from regex match) return col + m.Groups["row"].Value; }
结果应该看起来像这样(为了简洁,我删除了细胞分解):
Formula: Z1 Modified: AA1 Formula: ZZ1 Modified: AAA1 Formula: AZ1 Modified: BA1 Formula: AZB1 Modified: AZC1 Formula: BZZ2 Modified: CAAA2 Formula: =SUM($B$99:B99) Modified: =SUM($B$99:C99) Formula: =SUM($F99:F99) Modified: =SUM($F99:G99) Formula: =(SUM($B$0:B0)/SUM(1!$B$11:22!B33) -1) Modified: =(SUM($B$0:C0)/SUM(1!$B$11:22!C33) -1) Formula: =SUM(X80:Z1) Modified: =SUM(Y80:AA1) Formula: =A0 + B1 - C2 + Z5 Modified: =B0 + C1 - D2 + AA5 Formula: =C0+ B1 Modified: =D0+ C1 Formula: =$B$0+ AC1 Modified: =$B$0+ AD1 Formula: =AA12-ZZ34 + AZ1 - BZ2 - BX3 + BZX4 Modified: =AB12-AAA34 + BA1 - CA2 - BY3 + BZY4 Formula: =SUMX2MY2(A2:A8,B2:B8) Modified: =SUMX2MY2(B2:B8,C2:C8) Not a match: =$B$40 + 50 - 20
你确定你没有把这个过于复杂,对吧? 这是Excel本身的东西。 示例:在上例中,高亮显示单元B100。 在单元格的轮廓中注意,单元格的右下angular有一个小黑框。 这让你自动填充。 单击该黑框并将其右移(到单元格C100)。 你应该只有一列自动填充,C100应该有= SUM($ B $ 99:C99)。 如果你拖下来,你会得到= SUM($ B $ 99:B100)。
如果你的目标是在C#中重复这种行为,我猜想最好的办法是找出如何挂钩到Excel的自动填充function。 我不知道如何在C#中做到这一点,但他们当然可以在VBA中使用(您可以只logging一个macros,执行上述步骤,然后查看生成的代码以查看AutoFill VBA代码)。
希望有所帮助。
+! 自动化Excel并在那里完成工作。
但是,如果你一心想用C#来做,你可以从这里开始http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html 。 也许一旦你消化所有的标记化公式的规则,你就可以创build一个RE。