Подтвердить что ты не робот

Разделение CamelCase

Это все asp.net С#.

У меня есть перечисление

public enum ControlSelectionType 
{
    NotApplicable = 1,
    SingleSelectRadioButtons = 2,
    SingleSelectDropDownList = 3,
    MultiSelectCheckBox = 4,
    MultiSelectListBox = 5
}

Численное значение этого параметра сохраняется в моей базе данных. Я отображаю это значение в datagrid.

<asp:boundcolumn datafield="ControlSelectionTypeId" headertext="Control Type"></asp:boundcolumn>

Идентификатор ничего не значит для пользователя, поэтому я изменил столбец boundcolumn на столбец шаблона со следующим.

<asp:TemplateColumn>
    <ItemTemplate>
        <%# Enum.Parse(typeof(ControlSelectionType), DataBinder.Eval(Container.DataItem, "ControlSelectionTypeId").ToString()).ToString()%>
    </ItemTemplate>
</asp:TemplateColumn>

Это намного лучше... Тем не менее, было бы здорово, если бы была простая функция, которую я мог бы разместить вокруг Enum, чтобы разбить ее на случай Camel, чтобы слова хорошо переносились в datagrid.

Примечание. Я полностью понимаю, что есть лучшие способы сделать все это. Этот экран используется исключительно внутри, и я просто хочу быстро взломать его, чтобы отобразить его немного лучше.

4b9b3361

Ответ 1

Действительно, регулярное выражение/замена - это способ, как описано в другом ответе, однако это также может быть полезно для вас, если вы хотите пойти в другом направлении

    using System.ComponentModel;
    using System.Reflection;

...

    public static string GetDescription(System.Enum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());
        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attributes.Length > 0)
            return attributes[0].Description;
        else
            return value.ToString();
    }

это позволит вам определить ваш Enums как

public enum ControlSelectionType 
{
    [Description("Not Applicable")]
    NotApplicable = 1,
    [Description("Single Select Radio Buttons")]
    SingleSelectRadioButtons = 2,
    [Description("Completely Different Display Text")]
    SingleSelectDropDownList = 3,
}

Взято из

http://www.codeguru.com/forum/archive/index.php/t-412868.html

Ответ 3

Это регулярное выражение (^[a-z]+|[A-Z]+(?![a-z])|[A-Z][a-z]+) может использоваться для извлечения всех слов из имени camelCase или PascalCase. Он также работает с сокращениями в любом месте внутри.

  • MyHTTPServer будет содержать ровно 3 совпадения: My, HTTP, Server
  • myNewXMLFile будет содержать 4 совпадения: My, New, XML, File

Затем вы можете объединить их в одну строку, используя string.Join.

string name = "myNewUIControl";
string[] words = Regex.Matches(name, "(^[a-z]+|[A-Z]+(?![a-z])|[A-Z][a-z]+)")
    .OfType<Match>()
    .Select(m => m.Value)
    .ToArray();
string result = string.Join(" ", words);

Ответ 4

Если С# 3.0 - это опция, вы можете использовать следующий однострочный файл для выполнения задания:


Regex.Matches(YOUR_ENUM_VALUE_NAME, "[A-Z][a-z]+").OfType<Match>().Select(match => match.Value).Aggregate((acc, b) => acc + " " + b).TrimStart(' ');

Ответ 5

Ответ Tillito не обрабатывает строки, уже содержащие пробелы, или Акронимы. Это исправление:

public static string SplitCamelCase(string input)
{
    return Regex.Replace(input, "(?<=[a-z])([A-Z])", " $1", RegexOptions.Compiled);
}

Ответ 6

Здесь используется метод расширения, который позволяет обрабатывать числа и несколько символов верхнего регистра, а также позволяет использовать аббревиатуры верхнего предела в последней строке:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Web.Configuration;

namespace System
{
    /// <summary>
    /// Extension methods for the string data type
    /// </summary>
    public static class ConventionBasedFormattingExtensions
    {
        /// <summary>
        /// Turn CamelCaseText into Camel Case Text.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <remarks>Use AppSettings["SplitCamelCase_AllCapsWords"] to specify a comma-delimited list of words that should be ALL CAPS after split</remarks>
        /// <example>
        /// wordWordIDWord1WordWORDWord32Word2
        /// Word Word ID Word 1 Word WORD Word 32 Word 2
        /// 
        /// wordWordIDWord1WordWORDWord32WordID2ID
        /// Word Word ID Word 1 Word WORD Word 32 Word ID 2 ID
        /// 
        /// WordWordIDWord1WordWORDWord32Word2Aa
        /// Word Word ID Word 1 Word WORD Word 32 Word 2 Aa
        /// 
        /// wordWordIDWord1WordWORDWord32Word2A
        /// Word Word ID Word 1 Word WORD Word 32 Word 2 A
        /// </example>
        public static string SplitCamelCase(this string input)
        {
            if (input == null) return null;
            if (string.IsNullOrWhiteSpace(input)) return "";

            var separated = input;

            separated = SplitCamelCaseRegex.Replace(separated, @" $1").Trim();

            //Set ALL CAPS words
            if (_SplitCamelCase_AllCapsWords.Any())
                foreach (var word in _SplitCamelCase_AllCapsWords)
                    separated = SplitCamelCase_AllCapsWords_Regexes[word].Replace(separated, word.ToUpper());

            //Capitalize first letter
            var firstChar = separated.First(); //NullOrWhiteSpace handled earlier
            if (char.IsLower(firstChar))
                separated = char.ToUpper(firstChar) + separated.Substring(1);

            return separated;
        }

        private static readonly Regex SplitCamelCaseRegex = new Regex(@"
            (
                (?<=[a-z])[A-Z0-9] (?# lower-to-other boundaries )
                |
                (?<=[0-9])[a-zA-Z] (?# number-to-other boundaries )
                |
                (?<=[A-Z])[0-9] (?# cap-to-number boundaries; handles a specific issue with the next condition )
                |
                (?<=[A-Z])[A-Z](?=[a-z]) (?# handles longer strings of caps like ID or CMS by splitting off the last capital )
            )"
            , RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace
        );

        private static readonly string[] _SplitCamelCase_AllCapsWords =
            (WebConfigurationManager.AppSettings["SplitCamelCase_AllCapsWords"] ?? "")
                .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(a => a.ToLowerInvariant().Trim())
                .ToArray()
                ;

        private static Dictionary<string, Regex> _SplitCamelCase_AllCapsWords_Regexes;
        private static Dictionary<string, Regex> SplitCamelCase_AllCapsWords_Regexes
        {
            get
            {
                if (_SplitCamelCase_AllCapsWords_Regexes == null)
                {
                    _SplitCamelCase_AllCapsWords_Regexes = new Dictionary<string,Regex>();
                    foreach(var word in _SplitCamelCase_AllCapsWords)
                        _SplitCamelCase_AllCapsWords_Regexes.Add(word, new Regex(@"\b" + word + @"\b", RegexOptions.Compiled | RegexOptions.IgnoreCase));
                }

                return _SplitCamelCase_AllCapsWords_Regexes;
            }
        }
    }
}

Ответ 7

Вы можете использовать методы расширения С#

        public static string SpacesFromCamel(this string value)
        {
            if (value.Length > 0)
            {
                var result = new List<char>();
                char[] array = value.ToCharArray();
                foreach (var item in array)
                {
                    if (char.IsUpper(item) && result.Count > 0)
                    {
                        result.Add(' ');
                    }
                    result.Add(item);
                }

                return new string(result.ToArray());
            }
            return value;
        }

Тогда вы можете использовать его как

var result = "TestString".SpacesFromCamel();

Результат будет

Тестовая строка

Ответ 8

public enum ControlSelectionType    
{   
    NotApplicable = 1,   
    SingleSelectRadioButtons = 2,   
    SingleSelectDropDownList = 3,   
    MultiSelectCheckBox = 4,   
    MultiSelectListBox = 5   
} 
public class NameValue
{
    public string Name { get; set; }
    public object Value { get; set; }
}    
public static List<NameValue> EnumToList<T>(bool camelcase)
        {
            var array = (T[])(Enum.GetValues(typeof(T)).Cast<T>()); 
            var array2 = Enum.GetNames(typeof(T)).ToArray<string>(); 
            List<NameValue> lst = null;
            for (int i = 0; i < array.Length; i++)
            {
                if (lst == null)
                    lst = new List<NameValue>();
                string name = "";
                if (camelcase)
                {
                    name = array2[i].CamelCaseFriendly();
                }
                else
                    name = array2[i];
                T value = array[i];
                lst.Add(new NameValue { Name = name, Value = value });
            }
            return lst;
        }
        public static string CamelCaseFriendly(this string pascalCaseString)
        {
            Regex r = new Regex("(?<=[a-z])(?<x>[A-Z])|(?<=.)(?<x>[A-Z])(?=[a-z])");
            return r.Replace(pascalCaseString, " ${x}");
        }

//In  your form 
protected void Button1_Click1(object sender, EventArgs e)
        {
            DropDownList1.DataSource = GeneralClass.EnumToList<ControlSelectionType  >(true); ;
            DropDownList1.DataTextField = "Name";
            DropDownList1.DataValueField = "Value";

            DropDownList1.DataBind();
        }

Ответ 9

Решение от Eoin Campbell работает хорошо, за исключением случаев, когда у вас есть веб-служба.

Вам нужно будет сделать следующее, поскольку атрибут описания не может быть сериализуем.

[DataContract]
public enum ControlSelectionType
{
    [EnumMember(Value = "Not Applicable")]
    NotApplicable = 1,
    [EnumMember(Value = "Single Select Radio Buttons")]
    SingleSelectRadioButtons = 2,
    [EnumMember(Value = "Completely Different Display Text")]
    SingleSelectDropDownList = 3,
}


public static string GetDescriptionFromEnumValue(Enum value)
{
    EnumMemberAttribute attribute = value.GetType()
        .GetField(value.ToString())
        .GetCustomAttributes(typeof(EnumMemberAttribute), false)
        .SingleOrDefault() as EnumMemberAttribute;
    return attribute == null ? value.ToString() : attribute.Value;
}

Ответ 10

У меня также есть enum, который мне пришлось отделить. В моем случае этот метод решил проблему -

string SeparateCamelCase(string str)
{
    for (int i = 1; i < str.Length; i++)
    {
        if (char.IsUpper(str[i]))
        {
            str = str.Insert(i, " ");
            i++;
        }
    }
    return str;
}

Ответ 11

Использование LINQ:

var chars = ControlSelectionType.NotApplicable.ToString().SelectMany((x, i) => i > 0 && char.IsUpper(x) ? new char[] { ' ', x } : new char[] { x });

Console.WriteLine(new string(chars.ToArray()));

Ответ 12

И если вы не хотите использовать regex - попробуйте следующее:

public static string SeperateByCamelCase(this string text, char splitChar = ' ') {

        var output = new StringBuilder();

        for (int i = 0; i < text.Length; i++)
        {
            var c = text[i];

            //if not the first and the char is upper
            if (i > 0 && char.IsUpper(c)) {

                var wasLastLower = char.IsLower(text[i - 1]);

                if (i + 1 < text.Length) //is there a next
                {
                    var isNextUpper = char.IsUpper(text[i + 1]);

                    if (!isNextUpper) //if next is not upper (start of a word).
                    {
                        output.Append(splitChar);
                    }
                    else if (wasLastLower) //last was lower but i'm upper and my next is an upper (start of an achromin). 'abcdHTTP' 'abcd HTTP'
                    {
                        output.Append(splitChar);
                    }
                }
                else
                {
                    //last letter - if its upper and the last letter was lower 'abcd' to 'abcd A'
                    if (wasLastLower)
                    {
                        output.Append(splitChar);
                    }
                }
            }

            output.Append(c);
        }


        return output.ToString();

    }

Пропускает эти тесты, он не любит числа, но мне это не нужно.

    [TestMethod()]
    public void ToCamelCaseTest()
    {

        var testData = new string[] { "AAACamel", "AAA", "SplitThisByCamel", "AnA", "doesnothing", "a", "A", "aasdasdAAA" };
        var expectedData = new string[] { "AAA Camel", "AAA", "Split This By Camel", "An A", "doesnothing", "a", "A", "aasdasd AAA" };

        for (int i = 0; i < testData.Length; i++)
        {
            var actual = testData[i].SeperateByCamelCase();
            var expected = expectedData[i];
            Assert.AreEqual(actual, expected);
        }

    }

Ответ 13

Попробуйте это:

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        Console
            .WriteLine(
                SeparateByCamelCase("TestString") == "Test String" // True
            );
    }

    public static string SeparateByCamelCase(string str)
    {
        return String.Join(" ", SplitByCamelCase(str));
    }

    public static IEnumerable<string> SplitByCamelCase(string str) 
    {
        if (str.Length == 0) 
            return new List<string>();

        return 
            new List<string> 
            { 
                Head(str) 
            }
            .Concat(
                SplitByCamelCase(
                    Tail(str)
                )
            );
    }

    public static string Head(string str)
    {
        return new String(
                    str
                        .Take(1)
                        .Concat(
                            str
                                .Skip(1)
                                .TakeWhile(IsLower)
                        )
                        .ToArray()
                );
    }

    public static string Tail(string str)
    {
        return new String(
                    str
                        .Skip(
                            Head(str).Length
                        )
                        .ToArray()
                );
    }

    public static bool IsLower(char ch) 
    {
        return ch >= 'a' && ch <= 'z';
    }
}

Посмотреть образец онлайн

Ответ 14

Простая версия, похожая на некоторые из вышеперечисленных, но с логикой, чтобы не вставлять разделитель автоматически (который по умолчанию является пробелом, но может быть любым символом), если он уже есть в текущей позиции.

Использует StringBuilder вместо "мутирующих" строк.

public static string SeparateCamelCase(this string value, char separator = ' ') {

    var sb = new StringBuilder();
    var lastChar = separator;

    foreach (var currentChar in value) {

        if (char.IsUpper(currentChar) && lastChar != separator)
            sb.Append(separator);

        sb.Append(currentChar);

        lastChar = currentChar;
    }

    return sb.ToString();
}

Пример:

Input  : 'ThisIsATest'
Output : 'This Is A Test'

Input  : 'This IsATest'
Output : 'This Is A Test' (Note: Still only one space between 'This' and 'Is')

Input  : 'ThisIsATest' (with separator '_')
Output : 'This_Is_A_Test'