using System; using System.Text.RegularExpressions; namespace FlexFramework.Excel { /// /// A value which represents the position of a in a /// public struct Address : IEquatable
{ #region Equality members bool IEquatable
.Equals(Address other) { return Column == other.Column && Row == other.Row; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; return obj is Address && Equals((Address)obj); } public override int GetHashCode() { unchecked { return (Column * 397) ^ Row; } } #endregion /// /// One-based column index /// public int Column { get; private set; } /// /// One-based row index /// public int Row { get; private set; } /// /// Initializes a new instance of the Address class /// /// Excel cell address; e.g. A1 /// public Address(string address) { var column = Regex.Match(address, "^[A-Z]+"); var row = Regex.Match(address, "\\d+$"); if (!column.Success || !row.Success) throw new FormatException("Invalid address: " + address); Column = ParseColumn(column.Value); Row = int.Parse(row.Value); } /// /// Initializes a new instance of the Address class /// /// One-based column index /// One-based row index public Address(int column, int row) { Column = column; Row = row; } /// /// Column name; e.g. A /// public string ColumnName { get { return ParseColumn(Column); } } public override string ToString() { return string.Format("{0}{1}", ColumnName, Row); } public static bool operator ==(Address address, Address other) { return address.Row == other.Row && address.Column == other.Column; } public static bool operator !=(Address address, Address other) { return address.Row != other.Row || address.Column != other.Column; } public static bool operator >=(Address address, Address other) { return address.Row >= other.Row && address.Column >= other.Column; } public static bool operator <=(Address address, Address other) { return address.Row <= other.Row && address.Column <= other.Column; } public static bool operator >(Address address, Address other) { return address.Row > other.Row && address.Column > other.Column; } public static bool operator <(Address address, Address other) { return address.Row < other.Row && address.Column < other.Column; } public static Range operator +(Address from, Address to) { return new Range(from, to); } public static Address operator >>(Address address, int column) { return new Address(address.Column + column, address.Row); } public static Address operator <<(Address address, int column) { return new Address(address.Column - column, address.Row); } public static Address operator +(Address address, int row) { return new Address(address.Column, address.Row + row); } public static Address operator -(Address address, int row) { return new Address(address.Column, address.Row - row); } /// /// Parse one-based column index to excel-style /// /// One-based column index /// Converted column index in excel-style public static string ParseColumn(int column) { if (column <= 0) throw new ArgumentException("Column value must be greater than 0"); if (column <= 26) return Convert.ToChar(column + 64).ToString(); var div = column / 26; var mod = column % 26; if (mod != 0) return ParseColumn(div) + ParseColumn(mod); mod = 26; div--; return ParseColumn(div) + ParseColumn(mod); } /// /// Parse excel-style column to one-based index /// /// Excel-style column /// Converted one-based column index /// public static int ParseColumn(string column) { if (!Regex.IsMatch(column, "^[A-Z]+$")) throw new FormatException("Invalid address: " + column); var digits = new int[column.Length]; for (var i = 0; i < column.Length; ++i) digits[i] = Convert.ToInt32(column[i]) - 64; var mul = 1; var res = 0; for (var pos = digits.Length - 1; pos >= 0; --pos) { res += digits[pos] * mul; mul *= 26; } return res; } /// /// Check if the given address is valid /// /// /// True if valid public static bool IsValid(string address) { return Regex.IsMatch(address, "^[A-Z]+\\d+$"); } } }