2009-05-12 6 views
2

Ich möchte Excel-Formel in C# AutoFill implementieren.Welcher reguläre Ausdruck kann Excel-Spaltennamen in einer Formel in C# auswählen?

Nehmen wir an, diese Formel auf B100 befindet:

=SUM($B$99:B99) 

ich diese Formel anders bei C100 machen wollen:

=SUM($B$99:C99) 

Diese Formel ist nur ein Beispiel. Einige konkrete Beispiele sind:

=(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} 

(betrachten {0} und {1} sind in der Tat, Zahlen)

Was ich brauche zu tun, die allgemein ist diese Spaltennamen zu wählen und " erhöhen "sie. Spaltennamen, die von $ in Formeln umgeben sind, sollten nicht aktualisiert werden.

Wie identifiziert man diese Felder mit Regex?

+0

Wie zugreifen Sie diese Formeln? Es sieht so aus, als würden Sie direkt über Interop oder Ähnliches mit Excel interagieren und die Formel jeder Zelle (oder einer Reihe von Zellen) überprüfen und die Ersetzungsroutine für gültige Übereinstimmungen ausführen. Ist es sicher anzunehmen, dass Sie diesen Teil heruntergefahren haben und nur die Regex-/Spalteninkrement-Routine wollen? –

+0

Hallo Ahmad, ich mache einige Blatt-Setup, erstellen es dynamisch, und es gibt einige Formeln, die ich in dieses Blatt einfügen muss. Die meisten von ihnen sind nicht nur Zelle, sondern ganze Zeilen. Was ich tun muss, ist diese Formeln für jede Zelle zu ändern. Aber ich gab es auf, ich versuche eine neue und schnellere Lösung. –

Antwort

2

Hier ist eine Regex-Lösung, die sich ausschließlich mit Formeln befasst. Ich überlasse Ihnen das Excel-Zeug. Vorausgesetzt, Sie haben eine Sammlung von Strings, die Ihre Formeln repräsentieren, können Sie sie durchlaufen, um Ihre Spaltennamen zu erhöhen.

Einige Kommentare:

  • ** Test Dieser gründlich ** Vielleicht ein Blatt manuell tun und Ihre Bemühungen mit den generierten Ergebnisse vergleichen!.
  • Dies sollte nicht versehentlich Funktionsnamen ändern, die dem Zellennamensmuster entsprechen. Wenn Sie wissen, dass Ihre Formeln Excel-Funktionsnamen enthalten, die Zahlen enthalten, halten Sie nach ihnen Ausschau und - noch einmal - ** überprüfen Sie die Ergebnisse **.
  • Die Regex überprüft nicht, was Sie füttern, es ist eine Formel - ich nehme an, Sie verwenden nur Formeln. Mit anderen Worten, ich habe nicht überprüft, dass die Zeichenfolge mit einem "=" - Zeichen beginnt. Wenn Sie beabsichtigen, für andere Zellenwerte keine Formeln zu verwenden, fügen Sie einen Check hinzu, in dem IsMatch im if-Zweig mithilfe von formula.StartsWith ("=") verwendet wird.Um zu verstehen, was ich meine, fügen Sie eine zusätzliche Testzeichenfolge zu meiner Stichprobe hinzu, z. B. "Check out T4 generation" - wenn keine StartsWith ("=") Prüfung durchgeführt wird, wird T4 zu U4.

Das Regex-Muster war eigentlich der einfache Teil. Es passt nur zu einer beliebigen Buchstaben-Nummer-Sequenz und ignoriert die Zellenarten $ A $ 1 und $ A1. Der schwierige Teil war die Logik, die Spalte zu erhöhen. Ich habe Kommentare hinzugefügt, um das Bit zu verdeutlichen, also schnapp mir etwas Kaffee und lese es über :)

Ich bin sicher, dass dies verbessert werden könnte, aber dafür habe ich Zeit.

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>[A-Z]+)(?<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>[A-Z]+) # 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; 
} 

Die Ergebnisse aussehen sollte wie folgt aus (ich die Zelle Zusammenbruch der Kürze entfernt):

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 
0

Sie sind sicher, dass Sie das nicht zu kompliziert machen, oder? Dies ist etwas, was Excel nativ tut. Beispiel: Markieren Sie im obigen Beispiel Zelle B100. Beachten Sie im Umriss der Zelle, dass sich in der unteren rechten Ecke der Zelle ein kleines schwarzes Feld befindet. Dadurch können Sie AutoAusfüllen. Klicken Sie auf das schwarze Feld und ziehen Sie es nach rechts (zur Zelle C100). Sie sollten nur AutoFill über eine Spalte haben, und C100 sollte = SUM ($ B $ 99: C99) haben. Und wenn Sie stattdessen nach unten ziehen, erhalten Sie = SUMME ($ B $ 99: B100).

Wenn Ihr Ziel ist, dieses Verhalten in C# zu wiederholen, würde ich vermuten, dass der beste Weg, dies zu tun, herauszufinden, wie Sie in Excel AutoFill-Funktionen einhaken. Ich weiß nicht genau, wie Sie dies in C# tun würden, aber sicherlich sind sie in VBA verfügbar (und Sie können einfach ein Makro aufzeichnen, die obigen Schritte ausführen und dann den generierten Code betrachten, um den AutoFill-VBA-Code zu sehen).

Hoffe, dass hilft.

+0

Danke, Caleb. Ja, ich versuche dies in C# -Code zu tun. –

0

+! um Excel zu automatisieren und die Arbeit dort zu erledigen.

Wenn Sie jedoch in C# darauf festgelegt sind, können Sie hier beginnen http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html. Wenn Sie alle Regeln für das Token einer Formel verdaut haben, können Sie möglicherweise eine RE erstellen.

+0

Coole Verbindung, danke für das Teilen! Er stellte auch eine C# -Version in einem anderen Beitrag zur Verfügung: http://ewbi.blogs.com/developts/2007/03/excel_formula_p.html –

Verwandte Themen