我想从动态生成的单元格引用列表中创建一个Excel.Range对象。
Excel.Range outputRange = sheet.get_Range(strCellRange, Type.Missing);
由于strCellRange可能变得非常大,因此它会提供com异常。 因此,我希望简化它以使用union进行范围表示法。
e.g。
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";
答案 0 :(得分:3)
加扬,
在VBA
中,你可以强制你的直接字符串到
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
答案 1 :(得分:2)
这可能是一个起点(它不适用于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);
}
}
答案 2 :(得分:1)
<强> 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的解决方案
Excel.Range outputRange = sheet.get_Range(strCellRange, Type.Missing);
strCellRange = Application.Union(outputRange, outputRange).Address(false, false);
答案 3 :(得分:1)
首先有一些类包含引用...
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...
}
那么算法和方法...... 在传递给此方法之前,需要将单元格列表放在List中并排序。
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;
}
希望这有助于某人。
答案 4 :(得分:0)
我认为没有任何方法可以检索长范围的细胞参考。我宁愿选择完整的工作表,然后通过编码进行导航。