C#中是否有方法检查字符串是否为有效标识符

C#中是否有方法检查字符串是否为有效标识符,c#,identifier,C#,Identifier,在Java中,字符类上有称为isJavaIdentifierStart和isJavaIdentifierPart的方法,可以用来判断字符串是否是有效的Java标识符,如下所示: public boolean isJavaIdentifier(String s) { int n = s.length(); if (n==0) return false; if (!Character.isJavaIdentifierStart(s.charAt(0))) return fal

在Java中,字符类上有称为
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;
}
public boolean isJavaIdentifier(字符串s){
int n=s.长度();
如果(n==0)返回false;
如果(!Character.isJavaIdentifierStart(s.charAt(0)))
返回false;
对于(int i=1;i

C#是否有类似的功能?

这可以使用反射来完成-请参见是:

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

从这里开始:

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

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

  • 将提供程序缓存在静态变量中

    这将导致您只需要创建一次,但会减慢类型加载速度

  • 通过自行创建Microsoft.CSharp.CSharpCodeProvider实例,直接创建提供程序

    这将同时跳过配置文件解析

  • 编写代码来实现自我检查

    如果您这样做,您可以最大程度地控制它的实现方式,这可以帮助您在需要时优化性能。有关C#标识符的完整词汇语法,请参见第2.2.4节


  • 基本上是这样的:

    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);
    

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

    您可以在此处找到实施要点:

    它基于标识符()的MSDN文档

    在这里进行巫术

    在.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的旧版本中-查看mono sourcecode后:

    CodeDomProvider.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  
    
    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      } 
    
    然后是CSharpCodeProvider.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  
    
    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);
    }
    
    protectedoverride bool IsValidIdentifier(字符串标识符)
    {
    if(标识符==null | |标识符.长度==0)
    返回false;
    if(关键字稳定==null)
    FillKeywordTable();
    if(关键字stable.Contains(标识符))
    返回false;
    如果(!是\u标识符\u开始\u字符(标识符[0]))
    返回false;
    for(int i=1;i='a'&&c='a'&&c='a'&&c='a'&&c='0'&&c='a'&&c='a'&&c='a'&&c='a'&&c='0'&&c由于是开源的,代码分析工具唾手可得,而且它们是为性能而编写的。(现在它们已经在预发布中)

    然而,我不能谈论加载程序集的性能成本

    使用nuget安装工具:

    Install-Package Microsoft.CodeAnalysis -Pre
    
    问你的问题:

    var isValid = Microsoft.CodeAnalysis.CSharp.SyntaxFacts.IsValidIdentifier("I'mNotValid");
    Console.WriteLine(isValid);     // False
    
    现在发布的项目提供了与Java类似的
    Microsoft.CodeAnalysis.CSharp.SyntaxFacts
    ,以及
    SyntaxFacts.IsIdentifierStartCharacter(char)
    SyntaxFacts.IsIdentifierPartCharacter(char)
    方法

    在这里,它正在使用,在一个简单的函数中,我使用它将名词短语(例如“开始日期”)转换为C#标识符(例如“开始日期”)。注意:我使用它进行大小写转换,并使用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));
        }
    

    这确实有一些性能影响,你应该知道。请参阅我的帖子了解更多信息。OMG 7 upvows,它甚至不工作,甚至在我修复代码之前都没有编译…在它脱机之前已经存档。这是一个有用的事实,但没有帮助,因为你没有解释如何使用它。我似乎找不到一个“Microsoft.CodeAnalysis"NuGet软件包,我似乎也找不到解释在哪里可以获得该库的官方页面。我在第一个设置中提供了链接:。它说明:
    NuGet安装Microsoft.CodeAnalysis#安装语言API和服务
    你应该安装
    Microsoft.CodeAnalysis.CSharp
    ,以获得C规则。它可能是同时检查“上下文关键字”是个好主意。您可以使用
    SyntaxFacts.GetKeywordKind(关键字)==SyntaxKind.None&&SyntaxFacts.getContextalKeyWordKind(关键字)==SyntaxKind.None
    检查字符串是否为保留关键字或上下文关键字,或者使用
    SyntaxFacts.GetKeywordKinds()获取完整列表。选择(SyntaxFacts.GetText)