代码之家  ›  专栏  ›  技术社区  ›  Alex

C中是否有方法检查字符串是否为有效标识符[重复]

  •  23
  • Alex  · 技术社区  · 16 年前

    在爪哇,有一些方法叫做 isJavaIdentifierStart isJavaIdentifierPart 关于字符类,它可以用来判断字符串是否是一个有效的Java标识符,如:

    public boolean isJavaIdentifier(String s) {
      int n = s.length();
      if (n==0) return false;
      if (!Character.isJavaIdentifierStart(s.charAt(0)))
          return false;
      for (int i = 1; i < n; i++)
          if (!Character.isJavaIdentifierPart(s.charAt(i)))
              return false;
      return true;
    }
    

    有这样的东西吗?

    8 回复  |  直到 8 年前
        1
  •  6
  •   Stefan Steiger Marco van de Voort    11 年前

    基本上是这样的:

    const string start = @"(\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl})";
    const string extend = @"(\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf})";
    Regex ident = new Regex(string.Format("{0}({0}|{1})*", start, extend));
    s = s.Normalize();
    return ident.IsMatch(s);
    
        2
  •  33
  •   Community Mohan Dere    9 年前

    对:

    // using System.CodeDom.Compiler;
    CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
    if (provider.IsValidIdentifier (YOUR_VARIABLE_NAME)) {
          // Valid
    } else {
          // Not valid
    }
    

    从这里: How to determine if a string is a valid variable name?

        3
  •  8
  •   Matthew Murdoch    14 年前

    我会对这里提供的其他解决方案保持警惕。调用codedomprovider.createprovider需要查找和分析machine.config文件以及app.config文件。这可能比检查自己的字符串所需的时间慢几倍。

    相反,我建议您进行以下更改之一:

    1. 在静态变量中缓存提供程序。

      这将导致您只创建它一次,但它将减慢类型加载的速度。

    2. 通过创建自己的Microsoft.CSharp.CSharpCodeProvider实例,直接创建提供程序

      这将跳过一起分析配置文件。

    3. 编写代码来实现自我检查。

      如果您这样做,您就可以最大限度地控制它的实现方式,如果需要的话,这可以帮助您优化性能。见第2.2.4节 C# language spec 对于C标识符的完整词汇语法。

        4
  •  4
  •   DrewDouglas    11 年前

    Roslyn 作为开源软件,代码分析工具就在您的指尖,它们是为性能而编写的。(现在他们在预发行版中)。

    但是,我不能谈论装载组件的性能成本。

    使用Nuget安装工具:

    Install-Package Microsoft.CodeAnalysis -Pre
    

    问你的问题:

    var isValid = Microsoft.CodeAnalysis.CSharp.SyntaxFacts.IsValidIdentifier("I'mNotValid");
    Console.WriteLine(isValid);     // False
    
        5
  •  4
  •   Stefan Steiger Marco van de Voort    8 年前

    在这里行尸走肉。

    在.NET core/dnx中,您可以使用Roslyn SyntaxFacts来完成它。

    Microsoft.CodeAnalysis.CSharp.SyntaxFacts.IsReservedKeyword(
            Microsoft.CodeAnalysis.CSharp.SyntaxFacts.GetKeywordKind("protected")
    );
    
    
    
    foreach (ColumnDefinition cl in tableColumns)
    {
        sb.Append(@"         public ");
        sb.Append(cl.DOTNET_TYPE);
        sb.Append(" ");
    
        // for keywords
        //if (!Microsoft.CodeAnalysis.CSharp.SyntaxFacts.IsValidIdentifier(cl.COLUMN_NAME))
        if (Microsoft.CodeAnalysis.CSharp.SyntaxFacts.IsReservedKeyword(
            Microsoft.CodeAnalysis.CSharp.SyntaxFacts.GetKeywordKind(cl.COLUMN_NAME)
            ))
            sb.Append("@");
    
        sb.Append(cl.COLUMN_NAME);
        sb.Append("; // ");
        sb.AppendLine(cl.SQL_TYPE);
    } // Next cl 
    


    或者在带有codedom的旧变体中-在查看单源代码后:

    代码域提供者.cs

    public virtual bool IsValidIdentifier (string value) 
    286         { 
    287             ICodeGenerator cg = CreateGenerator (); 
    288             if (cg == null) 
    289                 throw GetNotImplemented (); 
    290             return cg.IsValidIdentifier (value); 
    291         } 
    292  
    

    然后是csharpcodeprovider.cs

    public override ICodeGenerator CreateGenerator() 
    91      { 
    92 #if NET_2_0 
    93          if (providerOptions != null && providerOptions.Count > 0) 
    94              return new Mono.CSharp.CSharpCodeGenerator (providerOptions); 
    95 #endif 
    96          return new Mono.CSharp.CSharpCodeGenerator(); 
    97      } 
    

    然后是csharpcodegenerator.cs

    protected override bool IsValidIdentifier (string identifier)
    {
        if (identifier == null || identifier.Length == 0)
            return false;
    
        if (keywordsTable == null)
            FillKeywordTable ();
    
        if (keywordsTable.Contains (identifier))
            return false;
    
        if (!is_identifier_start_character (identifier [0]))
            return false;
    
        for (int i = 1; i < identifier.Length; i ++)
            if (! is_identifier_part_character (identifier [i]))
                return false;
    
        return true;
    }
    
    
    
    private static System.Collections.Hashtable keywordsTable;
    private static string[] keywords = new string[] {
        "abstract","event","new","struct","as","explicit","null","switch","base","extern",
        "this","false","operator","throw","break","finally","out","true",
        "fixed","override","try","case","params","typeof","catch","for",
        "private","foreach","protected","checked","goto","public",
        "unchecked","class","if","readonly","unsafe","const","implicit","ref",
        "continue","in","return","using","virtual","default",
        "interface","sealed","volatile","delegate","internal","do","is",
        "sizeof","while","lock","stackalloc","else","static","enum",
        "namespace",
        "object","bool","byte","float","uint","char","ulong","ushort",
        "decimal","int","sbyte","short","double","long","string","void",
        "partial", "yield", "where"
    };
    
    
    static void FillKeywordTable ()
    {
        lock (keywords) {
            if (keywordsTable == null) {
                keywordsTable = new Hashtable ();
                foreach (string keyword in keywords) {
                    keywordsTable.Add (keyword, keyword);
                }
            }
        }
    }
    
    
    
    static bool is_identifier_start_character (char c)
    {
        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '@' || Char.IsLetter (c);
    }
    
    static bool is_identifier_part_character (char c)
    {
        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c);
    }
    

    你得到这个代码:

    public static bool IsValidIdentifier (string identifier)
    {
        if (identifier == null || identifier.Length == 0)
            return false;
    
        if (keywordsTable == null)
            FillKeywordTable();
    
        if (keywordsTable.Contains(identifier))
            return false;
    
        if (!is_identifier_start_character(identifier[0]))
            return false;
    
        for (int i = 1; i < identifier.Length; i++)
            if (!is_identifier_part_character(identifier[i]))
                return false;
    
        return true;
    }
    
    
    internal static bool is_identifier_start_character(char c)
    {
        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '@' || char.IsLetter(c);
    }
    
    internal static bool is_identifier_part_character(char c)
    {
        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || char.IsLetter(c);
    }
    
    
    private static System.Collections.Hashtable keywordsTable;
    private static string[] keywords = new string[] {
        "abstract","event","new","struct","as","explicit","null","switch","base","extern",
        "this","false","operator","throw","break","finally","out","true",
        "fixed","override","try","case","params","typeof","catch","for",
        "private","foreach","protected","checked","goto","public",
        "unchecked","class","if","readonly","unsafe","const","implicit","ref",
        "continue","in","return","using","virtual","default",
        "interface","sealed","volatile","delegate","internal","do","is",
        "sizeof","while","lock","stackalloc","else","static","enum",
        "namespace",
        "object","bool","byte","float","uint","char","ulong","ushort",
        "decimal","int","sbyte","short","double","long","string","void",
        "partial", "yield", "where"
    };
    
    internal static void FillKeywordTable()
    {
        lock (keywords)
        {
            if (keywordsTable == null)
            {
                keywordsTable = new System.Collections.Hashtable();
                foreach (string keyword in keywords)
                {
                    keywordsTable.Add(keyword, keyword);
                }
            }
        }
    }
    
        6
  •  3
  •   Vermis LordDawnhunter    11 年前

    最近,我编写了一个扩展方法来验证字符串是否为有效的C标识符。

    您可以在这里找到实现的要点: https://gist.github.com/FabienDehopre/5245476

    它基于标识符的msdn文档( http://msdn.microsoft.com/en-us/library/aa664670(v=vs.71).aspx )

    public static bool IsValidIdentifier(this string identifier)
    {
        if (String.IsNullOrEmpty(identifier)) return false;
    
        // C# keywords: http://msdn.microsoft.com/en-us/library/x53a06bb(v=vs.71).aspx
        var keywords = new[]
                           {
                               "abstract",  "event",      "new",        "struct",
                               "as",        "explicit",   "null",       "switch",
                               "base",      "extern",     "object",     "this",
                               "bool",      "false",      "operator",   "throw",
                               "breal",     "finally",    "out",        "true",
                               "byte",      "fixed",      "override",   "try",
                               "case",      "float",      "params",     "typeof",
                               "catch",     "for",        "private",    "uint",
                               "char",      "foreach",    "protected",  "ulong",
                               "checked",   "goto",       "public",     "unchekeced",
                               "class",     "if",         "readonly",   "unsafe",
                               "const",     "implicit",   "ref",        "ushort",
                               "continue",  "in",         "return",     "using",
                               "decimal",   "int",        "sbyte",      "virtual",
                               "default",   "interface",  "sealed",     "volatile",
                               "delegate",  "internal",   "short",      "void",
                               "do",        "is",         "sizeof",     "while",
                               "double",    "lock",       "stackalloc",
                               "else",      "long",       "static",
                               "enum",      "namespace",  "string"
                           };
    
        // definition of a valid C# identifier: http://msdn.microsoft.com/en-us/library/aa664670(v=vs.71).aspx
        const string formattingCharacter = @"\p{Cf}";
        const string connectingCharacter = @"\p{Pc}";
        const string decimalDigitCharacter = @"\p{Nd}";
        const string combiningCharacter = @"\p{Mn}|\p{Mc}";
        const string letterCharacter = @"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}";
        const string identifierPartCharacter = letterCharacter + "|" +
                                               decimalDigitCharacter + "|" +
                                               connectingCharacter + "|" +
                                               combiningCharacter + "|" +
                                               formattingCharacter;
        const string identifierPartCharacters = "(" + identifierPartCharacter + ")+";
        const string identifierStartCharacter = "(" + letterCharacter + "|_)";
        const string identifierOrKeyword = identifierStartCharacter + "(" +
                                           identifierPartCharacters + ")*";
        var validIdentifierRegex = new Regex("^" + identifierOrKeyword + "$", RegexOptions.Compiled);
        var normalizedIdentifier = identifier.Normalize();
    
        // 1. check that the identifier match the validIdentifer regex and it's not a C# keyword
        if (validIdentifierRegex.IsMatch(normalizedIdentifier) && !keywords.Contains(normalizedIdentifier))
        {
            return true;
        }
    
        // 2. check if the identifier starts with @
        if (normalizedIdentifier.StartsWith("@") && validIdentifierRegex.IsMatch(normalizedIdentifier.Substring(1)))
        {
            return true;
        }
    
        // 3. it's not a valid identifier
        return false;
    }
    
        7
  •  2
  •   Steve Cooper    10 年前

    现在发布的 Roslyn 项目提供 Microsoft.CodeAnalysis.CSharp.SyntaxFacts SyntaxFacts.IsIdentifierStartCharacter(char) SyntaxFacts.IsIdentifierPartCharacter(char) 方法就像Java一样。

    在这里,它被使用,在一个简单的函数中,我用来把名词短语(例如“开始日期”)转换成C标识符(例如“开始日期”)。N. B我在用 Humanizer 进行驼色大小写转换,并检查Roslyn字符是否有效。

        public static string Identifier(string name)
        {
            Check.IsNotNullOrWhitespace(name, nameof(name));
    
            // trim off leading and trailing whitespace
            name = name.Trim();
    
            // should deal with spaces => camel casing;
            name = name.Dehumanize();
    
            var sb = new StringBuilder();
            if (!SyntaxFacts.IsIdentifierStartCharacter(name[0]))
            {
                // the first characters 
                sb.Append("_");
            }
    
            foreach(var ch in name)
            {
                if (SyntaxFacts.IsIdentifierPartCharacter(ch))
                {
                    sb.Append(ch);
                }
            }
    
            var result = sb.ToString();
    
            if (SyntaxFacts.GetKeywordKind(result) != SyntaxKind.None)
            {
                result = @"@" + result;
            }
    
            return result;
        }
    

    测验;

        [TestCase("Start Date", "StartDate")]
        [TestCase("Bad*chars", "BadChars")]
        [TestCase("   leading ws", "LeadingWs")]
        [TestCase("trailing ws   ", "TrailingWs")]
        [TestCase("class", "Class")]
        [TestCase("int", "Int")]
        [Test]
        public void CSharp_GeneratesDecentIdentifiers(string input, string expected)
        {
            Assert.AreEqual(expected, CSharp.Identifier(input));
        }
    
        8
  •  1
  •   Community Mohan Dere    9 年前

    这可以通过反射来完成-请参见 How to determine if a string is a valid variable name?

    推荐文章