1

我使用 VSTO 从 Excel 电子表格中获取命名范围列表:

public List<Name> GetNamedRanges(Workbook activeWorkbook)
{
    List<Name> namedRanges = new List<Name>();
    Name name;
    for (int i = 0; i < activeWorkbook.Names.Count; i++)
    {
        name = activeWorkbook.Names.Item(i + 1);
        if (!name.Value.Contains("#REF"))
        {
            namedRanges.Add(name);
        }       
    }
    return namedRanges;
}

这会以奇怪的顺序返回名称:

在此处输入图像描述

有没有人有一个简单的方法来按列顺序对名称范围进行排序。例如:

=Sheet1!$A$9:$B$172
=Sheet1!$C$9:$D$172
=Sheet1!$E$41:$F$172

4

3 回答 3

1

http://www.interact-sw.co.uk/iangblog/2007/12/13/natural-sorting获取代码并对其进行修改,使其按字符串长度(按数字拆分后)排序,然后按自然排序。限制是,如果您确实有不同名称的工作表,那么您的工作表也将按字符串长度排序,而不是按 asciinerical 排序。

public class ExcelNameComparer<T> : IComparer<IEnumerable<T>>
{
    /// <summary>
    /// Create a sequence comparer using the default comparer for T.
    /// </summary>
    public ExcelNameComparer()
    {
        comp = Comparer<T>.Default;
    }

    /// <summary>
    /// Create a sequence comparer, using the specified item comparer
    /// for T.
    /// </summary>
    /// <param name="comparer">Comparer for comparing each pair of
    /// items from the sequences.</param>
    public ExcelNameComparer(IComparer<T> comparer)
    {
        comp = comparer;
    }

    /// <summary>
    /// Object used for comparing each element.
    /// </summary>
    private IComparer<T> comp;


    /// <summary>
    /// Compare two sequences of T.
    /// </summary>
    /// <param name="x">First sequence.</param>
    /// <param name="y">Second sequence.</param>
    public int Compare(IEnumerable<T> x, IEnumerable<T> y)
    {
        using (IEnumerator<T> leftIt = x.GetEnumerator())
        using (IEnumerator<T> rightIt = y.GetEnumerator())
        {
            while (true)
            {
                bool left = leftIt.MoveNext();
                bool right = rightIt.MoveNext();

                if (!(left || right)) return 0;

                if (!left) return -1;
                if (!right) return 1;

                int lengthResult = leftIt.Current.ToString().Length.CompareTo(rightIt.Current.ToString().Length);
                if (lengthResult != 0) return lengthResult;

                int itemResult = comp.Compare(leftIt.Current, rightIt.Current);
                if (itemResult != 0) return itemResult;
            }
        }
    }

Func<string, object> convert = str =>
{
    try { return int.Parse(str); }
    catch { return str; }
};

现在运行实际排序:

    var lst = new List<string> { "Sheet1!$A$9:$B$172", "Sheet1!$AY$77:$AZ$172",     "Sheet1!$E$41:$F$172", "Sheet1!$A$10:$B$172", "Sheet1!$A$1:$B$172" };

    var sorted = lst.OrderBy(
        str => Regex.Split(str.Replace(" ", ""), "([0-9]+)").Select(convert),
        new ExcelNameComparer<object>());
    foreach (var sort in sorted)
    {
        System.Diagnostics.Debug.Print(sort);
    }

产量:

Sheet1!$A$1:$B$172
Sheet1!$A$9:$B$172
Sheet1!$A$10:$B$172
Sheet1!$E$41:$F$172
Sheet1!$AY$77:$AZ$172

于 2013-08-21T23:36:28.443 回答
0

我只是通过删除数字来完成的,然后按长度排序,然后按字母顺序排序,它非常混乱,但可以完成工作:

static public List<Name> GetNamedRangesInOrder(Workbook activeWorkbook)
{
    List<Name> namedRanges = GetNamedRanges(activeWorkbook);

    List<string> lstStringNameRanges = new List<string>();
    foreach (var item in namedRanges)
    {
        lstStringNameRanges.Add(RemoveDigits(item.RefersTo.ToString()));
    }

    IEnumerable<string> results = SortByLengthAndName(lstStringNameRanges);
    List<Name> sortedNamedRanges = new List<Name>();
    foreach (var item in results)
    {
        int index = -1;
        for (int i=0; i < namedRanges.Count; i++)
        {
            if (RemoveDigits(namedRanges[i].RefersTo.ToString()) == item.ToString())
            {
                index = i;
                break;
            }
        }
        sortedNamedRanges.Add(namedRanges[index]);
    }
    return sortedNamedRanges;

}

static public IEnumerable<string> SortByLengthAndName(IEnumerable<string> e)
{
    IEnumerable<string> query = e.OrderBy(x => x.Length).ThenBy(x => x).ToList();
    return query;
}

static public string RemoveDigits(string e)
{
    string str = new string((from c in e
            where char.IsLetter(c) || char.IsSymbol(c)
            select c).ToArray());

    return str;
}
于 2013-08-26T01:00:24.833 回答
0

在 Excel 中对它们进行排序,然后再次在工作簿中阅读。(是一个简单的方法。)

于 2013-08-21T07:24:49.800 回答