简化excel单元格列表以创build一个Range

我想从dynamic生成的单元格引用列表中创build一个Excel.Range对象。

Excel.Range outputRange = sheet.get_Range(strCellRange, Type.Missing); 

由于strCellRange可能会变得很大,因此会给出例外。 所以我想简化它与范围符号的联合。

例如

 string strCellRange = "F2,G2,H2,I2,J2,K2,L2,F7,G7,H7,I7,J7,K7,L7,F12,G12,H12,I12,J12,K12,L12,F17,G17,H17,I17,J17,K17,L17,F22,G22,H22,I22,J22,K22,L22,F27,G27,H27,I27,J27,K27,L27"; 

 string strCellRange = "F2:L2,F7:L7,F12:L12,F17:L17,F22:L22,F27:L27"; 
  1. 是否有任何Excel方法创build一个具有很多单元格引用的Range对象?
  2. 有一个已知的algorithm来实现上述简化(matrixalgorithm)?

加扬,

VBA你可以强制直接使用string

 Sub Test() Dim rng1 As Range Dim strCellRange As String strCellRange = "F2,G2,H2,I2,J2,K2,L2,F7,G7,H7,I7,J7,K7,L7,F12,G12,H12,I12,J12,K12,L12,F17,G17,H17,I17,J17,K17,L17,F22,G22,H22,I22,J22,K22,L22,F27,G27,H27,I27,J27,K27,L27" Set rng1 = Range(strCellRange) Set rng1 = Union(rng1, rng1) Debug.Print rng1.Address End Sub 

这可能是一个起点(它不适用于Z以外的列,并且不能识别矩形):

  private string CompactRangeStringByRows(string strCellRange) { SortedDictionary<int, SortedList<char, char>> rows = new SortedDictionary<int, SortedList<char, char>>(); foreach (string aCell in strCellRange.Split(new Char[] { ',' })) { char col = aCell[0]; int row = int.Parse(aCell.Substring(1, aCell.Length - 1)); SortedList<char, char> cols; if (!rows.TryGetValue(row, out cols)) { cols = new SortedList<char, char>(); rows[row] = cols; } cols.Add(col, col); } StringBuilder sb = new StringBuilder(); bool first = true; foreach (KeyValuePair<int, SortedList<char, char>> rowCols in rows) { char minCol = '0'; char maxCol = '0'; foreach (char col in rowCols.Value.Keys) { if (minCol == '0') { minCol = col; maxCol = col; } else { if (col == maxCol + 1) maxCol = col; else { AddRangeString(sb, first, rowCols.Key, minCol, maxCol); minCol = col; maxCol = col; first = false; } } } AddRangeString(sb, first, rowCols.Key, minCol, maxCol); first = false; } return sb.ToString(); } private void AddRangeString(StringBuilder sb, bool first, int row, char minCol, char maxCol) { if (!first) sb.Append(','); sb.Append(minCol); sb.Append(row); if (maxCol != minCol) { sb.Append(':'); sb.Append(maxCol); sb.Append(row); } } 

VBA

 Function Unionize(src As Range) As Range Dim cell As Range Dim unionizedRange As Range For Each cell In src If unionizedRange Is Nothing Then Set unionizedRange = cell Else Set unionizedRange = Union(unionizedRange, cell) End If Next Set Unionize = unionizedRange End Function 

C# (粗剪,没有通过编译器运行它的语法)

 Excel.Range Unionize(Excel.Range src) { Excel.Range unionizedRange; foreach (Excel.Range cell in src) { if (unionizedRange == null) { unionizedRange = cell; } Else { unionizedRange = Application.Union(unionizedRange, cell); } } return unionizedRange; } 

编辑 :基于@ brettdj的解决scheme

 Excel.Range outputRange = sheet.get_Range(strCellRange, Type.Missing); strCellRange = Application.Union(outputRange, outputRange).Address(false, false); 

首先有一些类持有引用…

 public class CellRef : IEquatable<CellRef> { public int Row { get; private set; } public int Col { get; private set; } // some more code... } public class CellRange : IEquatable<CellRange> { public CellRef Start { get; private set; } public CellRef Stop { get; private set; } // some more code... } 

然后algorithm和方法…在传递给这个方法之前,单元格列表需要放在一个List中并sorting

  public static string GetSimplifiedRangeString(List<CellRef> cellList) { #region Column wise simplify (identify lines) Dictionary<CellRef, CellRef> rowRanges = new Dictionary<CellRef, CellRef>(new CellRefEqualityComparer()); int currentRangeStart = 0; for (int currentRangeStop = 0; currentRangeStop < cellList.Count; currentRangeStop++) { CellRef currentCell = cellList[currentRangeStop]; CellRef previousCell = (currentRangeStop == 0) ? null : cellList[currentRangeStop - 1]; bool cont = IsContigousX(currentCell, previousCell); if (!cont) { currentRangeStart = currentRangeStop; } if (!rowRanges.ContainsKey(cellList[currentRangeStart])) rowRanges.Add(cellList[currentRangeStart], cellList[currentRangeStop]); else rowRanges[cellList[currentRangeStart]] = cellList[currentRangeStop]; } #endregion #region Row wise simplify (identify rectangles) List<CellRange> rangeList = new List<CellRange>(); foreach (KeyValuePair<CellRef, CellRef> range in rowRanges) { rangeList.Add(new CellRange(range.Key, range.Value)); } Dictionary<CellRange, CellRange> colRanges = new Dictionary<CellRange, CellRange>(new CellRangeEqualityComparer()); currentRangeStart = 0; for (int currentRangeStop = 0; currentRangeStop < rangeList.Count; currentRangeStop++) { CellRange currentCellRange = rangeList[currentRangeStop]; CellRange previousCellRange = (currentRangeStop == 0) ? null : rangeList[currentRangeStop - 1]; bool cont = IsContigousY(currentCellRange, previousCellRange); if (!cont) { currentRangeStart = currentRangeStop; } if (!colRanges.ContainsKey(rangeList[currentRangeStart])) colRanges.Add(rangeList[currentRangeStart], rangeList[currentRangeStop]); else colRanges[rangeList[currentRangeStart]] = rangeList[currentRangeStop]; } #endregion #region Simplify ranges (identify atomic lines and rectangles) StringBuilder retStr = new StringBuilder(); foreach (KeyValuePair<CellRange, CellRange> ranges in colRanges) { string rangePart = string.Empty; if (ranges.Key.Equals(ranges.Value)) { if (ranges.Key.Start.Equals(ranges.Key.Stop)) { rangePart = ranges.Key.Start.ToString(); } else { rangePart = ranges.Key.ToString(); } } else { rangePart = new CellRange(ranges.Key.Start, ranges.Value.Stop).ToString(); } if (retStr.Length == 0) { retStr.Append(rangePart); } else { retStr.Append("," + rangePart); } } return retStr.ToString(); #endregion } /// <summary> /// Checks whether the given two cells represent a line. /// </summary> /// <param name="currentCell">Line start</param> /// <param name="previousCell">Line end</param> /// <returns></returns> private static bool IsContigousX(CellRef currentCell, CellRef previousCell) { if (previousCell == null) return false; return (currentCell.Row == previousCell.Row) && (currentCell.Col == (previousCell.Col + 1)); } /// <summary> /// Checks whether the given two cells represents a rectangle. /// </summary> /// <param name="currentCellRange">Top-left cell</param> /// <param name="previousCellRange">Bottom-right cell</param> /// <returns></returns> private static bool IsContigousY(CellRange currentCellRange, CellRange previousCellRange) { if (previousCellRange == null) return false; bool sameVertically = (currentCellRange.Start.Col == previousCellRange.Start.Col) && (currentCellRange.Stop.Col == previousCellRange.Stop.Col); bool contigous = (currentCellRange.Start.Row == currentCellRange.Stop.Row) && (previousCellRange.Start.Row == previousCellRange.Stop.Row) && ((previousCellRange.Stop.Row + 1) == currentCellRange.Stop.Row); return sameVertically && contigous; } 

希望这有助于某人。

我不认为有任何方法来检索长单元格引用。 我宁愿采取完整的表格,然后通过编码导航。