使用代码在Excel Name Manager中对命名范围进行排序

时间:2013-08-21 07:22:14

标签: c# excel sorting vsto named-ranges

我使用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;
}

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

enter image description here

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

= Sheet 1中$ A $ 9:!$ B $ 172
工作表Sheet1 = $ C $ 9:$!d $ 172
= Sheet1!$ E $ 41:$ F $ 172

3 个答案:

答案 0 :(得分:1)

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

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!$ A $ 77:$ AZ $ 172

答案 1 :(得分:0)

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

答案 2 :(得分: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;
}