2009-12-01 19 views
20

मैं यह निर्धारित करने के लिए एक स्ट्रिंग एक वैध चर नाम है या नहीं, यह एक त्वरित तरीका (सी # में) की तलाश में हूं। मेरा पहला अंतर्ज्ञान यह करने के लिए कुछ रेगेक्स को चाबुक करना है, लेकिन मुझे आश्चर्य है कि ऐसा करने का एक बेहतर तरीका है या नहीं। शायद किसी तरह की गुप्त विधि को कहीं भी गहरा छुपाया जाता है जिसे कहीं भी IsThisAValidVariableName (स्ट्रिंग नाम) कहा जाता है, या ऐसा करने के लिए कुछ अन्य चालाक तरीका है जो रेगेक्स कौशल की कमी के कारण उत्पन्न हो सकती त्रुटियों से ग्रस्त नहीं है।यह निर्धारित करने के लिए कि कोई स्ट्रिंग वैध चर नाम है या नहीं?

+0

तुम्हारा मतलब सी # चर नाम है? और मुझे लगता है कि रेगेक्स आपकी सबसे अच्छी शर्त है जब तक कि आप अपनी छोटी सी पार्सर चीज़ (जो जांचने के लिए ऐसी छोटी सी चीज के लिए अधिक है) – Earlz

+0

यदि आप रेगेक्स का उपयोग कर रहे हैं तो सावधान रहना एक बात यह है कि कई यूनीकोड ​​चरित्र कक्षाएं हैं कि आपको ध्यान में रखना पड़ सकता है: http://msdn.microsoft.com/en-us/library/aa664670%28VS.71%29.aspx –

+0

रीगेक्स बोनस – bobince

उत्तर

42

इस प्रयास करें:।

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

आपको संदर्भित करने की आवश्यकता है इसके लिए 'System.CodeDom.Compiler' नामस्थान :-) – CesarGon

+15

हां। आपको उस कोड को एक विधि के अंदर, और कक्षा में विधि और YOUR_VARIABLE_NAME नामक एक चर को भी रखना होगा ...;-) – Gonzalo

+1

'CodeDomProvider' कितना महंगा है? –

1

अब जिस तरह से, के साथ साथ यह बहुत धीमी है, एक वर्ग/नाम स्थान के सदस्यों से अधिक पुनरावृति और (यदि परिलक्षित सदस्य ** ToString की जाँच करके तुलना करने के लिए प्रतिबिंब का उपयोग करने के लिए है) ** स्ट्रिंग इनपुट के समान है, इसके लिए असेंबली पहले से लोड होने की आवश्यकता है।

इसे करने का एक और तरीका (रेगेक्स के उपयोग को खत्म करने वाला एक लंबा रास्ता, पहले से उपलब्ध एंटरल स्कैनर/पार्सर का उपयोग करके) सी # कोड को पार्सिंग/लेक्सिंग पर सीमाएं और फिर सदस्य नामों (यानी चर) के लिए स्कैनिंग और इनपुट के रूप में उपयोग की जाने वाली स्ट्रिंग की तुलना में, उदाहरण के लिए, 'fooBar' नामक एक स्ट्रिंग इनपुट करें, फिर स्रोत (जैसे असेंबली या सी # कोड) निर्दिष्ट करें और विशेष रूप से सदस्यों की घोषणा के लिए विशेष रूप से देखने के विश्लेषण से स्कैन करें उदाहरण के लिए

 
private int fooBar; 

हां, यह जटिल है लेकिन एक शक्तिशाली समझ तब उत्पन्न होगी जब आप महसूस करेंगे कि कंपाइलर लेखकों क्या कर रहे हैं और सी # भाषा के बारे में आपके ज्ञान को उस स्तर तक बढ़ाएंगे जहां आप काफी अंतरंग हो वाक्यविन्यास और इसकी विशिष्टताएं।

+0

प्रश्न को गलत समझा। –

1

@ चरित्र के आसपास कुछ विशेष मामले हैं जो चेक करना भूल जाते हैं - अर्थात् '@' स्वयं मान्य पहचानकर्ता नहीं है, और न ही "@1foo" है। इन्हें पकड़ने के लिए, आप पहले जांच सकते हैं कि स्ट्रिंग एक कीवर्ड है या नहीं, फिर स्ट्रिंग की शुरुआत से @ हटाएं, और तब जांचें कि क्या बचा है वैध पहचानकर्ता है (@ वर्णों को अस्वीकार कर रहा है)।

यहां मैंने इसे पहचानकर्ताओं में यूनिकोड से बचने के अनुक्रमों को पार्स करने के लिए एक विधि के साथ जोड़ा है, और उम्मीद है कि सी # (5.0) यूनिकोड चरित्र जांच पूरी करें। इसका उपयोग करने के लिए, पहले कीवर्ड को संभालने के लिए TryParseRawIdentifier() पर कॉल करें, अनुक्रम अनुक्रम, स्वरूपण वर्ण (जो हटाए गए हैं), और क्रियात्मक पहचानकर्ता। इसके बाद, यह देखने के लिए कि पहले और बाद वाले वर्ण मान्य हैं या नहीं, परिणाम IsValidParsedIdentifier() पर भेजें। ध्यान दें कि TryParseRawIdentifier() से लौटे तार समान हैं और केवल अगर पहचानकर्ताओं को सी # के समान माना जाता है।

public static class CSharpIdentifiers 
{ 
    private static HashSet<string> _keywords = new HashSet<string> { 
     "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", 
     "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", 
     "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", 
     "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock", 
     "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", 
     "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", 
     "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", 
     "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", 
     "virtual", "void", "volatile", "while" 
    }; 

    public static IReadOnlyCollection<string> Keywords { get { return _keywords; } } 


    public static bool TryParseRawIdentifier(string str, out string parsed) 
    { 
     if (string.IsNullOrEmpty(str) || _keywords.Contains(str)) { parsed = null; return false; } 

     StringBuilder sb = new StringBuilder(str.Length); 

     int verbatimCharWidth = str[0] == '@' ? 1 : 0; 

     for (int i = verbatimCharWidth; i < str.Length;) //Manual increment 
     { 
      char c = str[i]; 

      if (c == '\\') 
      { 
       char next = str[i + 1]; 

       int charCodeLength; 
       if (next == 'u') charCodeLength = 4; 
       else if (next == 'U') charCodeLength = 8; 
       else { parsed = null; return false; } 
       //No need to check for escaped backslashes or special sequences like \n, 
       //as they not valid identifier characters 

       int charCode; 
       if (!TryParseHex(str.Substring(i + 2, charCodeLength), out charCode)) { parsed = null; return false; } 

       sb.Append(char.ConvertFromUtf32(charCodeLength)); //Handle characters above 2^16 by converting them to a surrogate pair 
       i += 2 + charCodeLength; 
      } 
      else if (char.GetUnicodeCategory(str, i) == UnicodeCategory.Format) 
      { 
       //Use (string, index) in order to handle surrogate pairs 
       //Skip this character 
       if (char.IsSurrogatePair(str, i)) i += 2; 
       else i += 1; 
      } 
      else 
      { 
       sb.Append(c); 
       i++; 
      } 
     } 

     parsed = sb.ToString(); 
     return true; 
    } 

    private static bool TryParseHex(string str, out int result) 
    { 
     return int.TryParse(str, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out result); 
     //NumberStyles.AllowHexSpecifier forces all characters to be hex digits 
    } 

    public static bool IsValidParsedIdentifier(string str) 
    { 
     if (string.IsNullOrEmpty(str)) return false; 

     if (!IsValidParsedIdentifierStart(str, 0)) return false; 

     int firstCharWidth = char.IsSurrogatePair(str, 0) ? 2 : 1; 

     for (int i = firstCharWidth; i < str.Length;) //Manual increment 
     { 
      if (!IsValidParsedIdentifierPart(str, i)) return false; 
      if (char.IsSurrogatePair(str, i)) i += 2; 
      else i += 1; 
     } 

     return true; 
    } 

    //(String, index) pairs are used instead of chars in order to support surrogate pairs 
    //(Unicode code-points above 2^16 represented using two 16-bit characters) 

    public static bool IsValidParsedIdentifierStart(string s, int index) 
    { 
     return s[index] == '_' || char.IsLetter(s, index) || char.GetUnicodeCategory(s, index) == UnicodeCategory.LetterNumber; 
    } 

    public static bool IsValidParsedIdentifierPart(string s, int index) 
    { 
     if (s[index] == '_' || (s[index] >= '0' && s[index] <= '9') || char.IsLetter(s, index)) return true; 

     switch (char.GetUnicodeCategory(s, index)) 
     { 
      case UnicodeCategory.LetterNumber: //Eg. Special Roman numeral characters (not covered by IsLetter()) 
      case UnicodeCategory.DecimalDigitNumber: //Includes decimal digits in other cultures 
      case UnicodeCategory.ConnectorPunctuation: 
      case UnicodeCategory.NonSpacingMark: 
      case UnicodeCategory.SpacingCombiningMark: 
      //UnicodeCategory.Format handled in TryParseRawIdentifier() 
       return true; 
      default: 
       return false; 
     } 
    } 
} 
0
public static bool IsIdentifier(string text) 
    { 
    if (string.IsNullOrEmpty(text)) 
     return false; 
    if (!char.IsLetter(text[0]) && text[0] != '_') 
     return false; 
    for (int ix = 1; ix < text.Length; ++ix) 
     if (!char.IsLetterOrDigit(text[ix]) && text[ix] != '_') 
      return false; 
    return true; 
    } 
संबंधित मुद्दे

 संबंधित मुद्दे