I thought this question was asked before but I tried Google but didn't find an answer. Maybe I used wrong keywords.
Is it possible to use regular expression to match valid C# namespace name?
Update:
Thanks everyone for your answers and research! This question is much more complex than I expected. As Oscar Mederos and Joey pointed out, a valid namespace cannot contain C# reserved keywords, and can contain a lot more Unicode characters than Latin letters.
But my current project only need to syntactically validate namespaces. So I accepted primfaktor's answer, but I upvoted all answers.
For me, this worked:
^using (#?[a-z_A-Z]\w+(?:\.#?[a-z_A-Z]\w+)*);$
It matches using lines in C# and returns the complete namespace in the first (and only) match group. You may want to remove ^ and $ to allow for indentation and trailing comments.
Example on RegExr.
I know that the question was how to validate a namespace using a regex, but another way to do it is to make the compiler do the work. I am not certain that what I have here catches 100% of all errors, it does work pretty well. I created this ValidationRule for a project on which I am currently working:
using System.CodeDom.Compiler;
using System.Windows.Controls;
using Microsoft.CSharp;
using System.Text.RegularExpressions;
namespace Com.Gmail.Birklid.Ray.CodeGeneratorTemplateDialog
{
public class NamespaceValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
var input = value as string;
if (string.IsNullOrWhiteSpace(value as string))
{
return new ValidationResult(false, "A namespace must be provided.");
}
else if (this.doubleDot.IsMatch(input))
{
return new ValidationResult(false, "'..' is not valid.");
}
var inputs = (value as string).Split('.');
foreach (var item in inputs)
{
if (!this.compiler.IsValidIdentifier(item))
{
return new ValidationResult(false, string.Format(cultureInfo, "'{0}' is invalid.", item));
}
}
return ValidationResult.ValidResult;
}
private readonly CodeDomProvider compiler = CSharpCodeProvider.CreateProvider("CSharp");
private readonly Regex doubleDot = new Regex("\\.\\.");
}
}
If you want to know if a string can be used as a namespace, you should refer to The C# Language Specifications and look at the grammar that validates the namespace.
The namespace should be a sequence of identifiers separated by a .. Example:
identifier
identifier.identifier
identifier.identifier.identifier
...
And what is an identifier?
available_identifier or #any_identifier
An available_identifier is an any_identifier but cannot be a keyword reserved by the language.
any_identifier is the following:
(_|letter)(letter|number)*
Edit:
I must say that this regex can be really really complicated. Take in count that it is necessary to check if no reserved keywords are used, and here is the list of the reserved keywords:
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
Can't you split the validation, maybe creating a method in C# or any other language to validate it instead of using only one regex?
To be honest, I suggest you any of those two things:
Implement a parser of that grammar (see the reference). You can do it either by hand or using tools like ANTLR
Implement a method that takes the string you want to validate (let's call it str) and write a file like:
namespace str
{
class A {}
}
and try to compile it :) using msbuild or any C# compiler. If it gives an error, then you know that word is not correct :)
How about this...
(?:[A-Z][a-zA-Z0-9\._]+)+[a-z0-9_]
Related
Is there a .net bug causing the following code to capitalise the S, giving "Ben’S Pies"?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Globalization;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
string value = "ben’s pies";
string titleCase = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(value);
Console.WriteLine(titleCase);
}
}
}
You can see the output at: https://rextester.com/ (where I tried it).
If you print a dump of the value:
string value = "ben’s pies";
Console.Write(string.Join(" ", value.Select(c => ((int)c).ToString("x4"))));
You'll get
0062 0065 006e 2019 0073 0020 0070 0069 0065 0073
Now, let's have a look for Unicode U+2019
https://www.fileformat.info/info/unicode/char/2019/index.htm
And we see that ’ is not an apostroph, but "RIGHT SINGLE QUOTATION MARK (U+2019)." That's why ToTitleCase does work right (it capitalizes the word after a punctuation - a quotation mark). To amend your example put apostroph instead of quotation:
string value = "ben's pies";
// Ben's Pies
string titleCase = CultureInfo.GetCultureInfo("en-US").TextInfo.ToTitleCase(value);
ToTitleCase does indeed seem to treat the right single quotation mark as a separator between the words it converts to title case. The documentation says:
the ToTitleCase method provides an arbitrary casing behavior which is not necessarily linguistically correct. A linguistically correct solution would require additional rules, and the current algorithm is somewhat simpler and faster. We reserve the right to make this API slower in the future.
I want to be able to use the contains function the same way the like operator works in sql. So when I call .contains(%This%%%%%%is%%my%string%%) from a list or whatever such as "This is my string " then the function will return true. I've done a lot of searching and it seems like a lot of people would like this function. So how can this be done or how can a custom like function with the same functionality be made?
EDIT
Thank you, for the quick response. I was able to use a regular expressions inside of my own custom Like function. Below is the code for anyone else who wants to use something similar to SQL Like. In this code the user would input the databaze value and then spaces in that value are replaced with .* to ignore anything in-between the values.Just like using the % to replace spaces and values in SQL. I can then use .Like on my string value called testValue that I am searching through to return true or false depending on if the words or whatever are in my string. I also added ToUpper to ignore the case.
//C# Like function
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace sqllinqstuff
{
class Program
{
static void Main(string[] args)
{
string testValue = "Big RED Car";
string databaze = "big red CAR";
string databaze3 = databaze.Replace(" ", ".*");
databaze3 = databaze3.Replace(" ", ".*");
Console.WriteLine(databaze3);
Console.WriteLine(testValue.Like(databaze3));
Console.Read();
}
}
public static class CaseyStringExtension
{
public static bool Like(this string str,string value)
{
if (!string.IsNullOrEmpty(str))
{
Regex r = new Regex(value.ToUpper());
if (r.IsMatch(str.ToUpper()))
return true;
}
return false;
}
}
}
The result of this test will be true.
The way this would be done is with Regex. The syntax is not the same as a SQL LIKE query so there will be a bit of a learning curve. This is a good tutorial site I often reference, it can get you started with the basics.
Translating your original string you asked about, the regex search pattern would be
.*This.*is.*my.*string.*
Once you get good at it you can do searches like this one I helped create for a password complexity checker
(?=^.{8,}$)(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_])(?=^.*[^\s].*$).*$
The above search looks for a string that has at least 8 characters with at least one lower case letter, one upper case letter, one special character, and no white-space characters.
Im trying to match properties in class. Example class:
public static string ComingSoonPage
{
get { return "/blog-coming-soon.aspx"; }
}
public static string EncodeBase64(string dataToEncode)
{
byte[] bytes = System.Text.ASCIIEncoding.UTF8.GetBytes(dataToEncode);
string returnValue = System.Convert.ToBase64String(bytes);
return returnValue;
}
Im using this kind of regex:
(?:public|private|protected)([\s\w]*)\s+(\w+)[^(]
It matches not only properties but also methods which is wrong. So i want remove from matches sentences that contains (. So it select all but not methods (which contains ( ). How can i achieve that.
Try matching the "{" and the "get {" instead
(public|private|protected|internal)[\s\w]*\s+(\w+)\s*\{\s*get\s*\{
UPDATE
Match only the name of the property
(?<=(public|private|protected|internal)[\s\w]*\s+)\w+(?=\s*\{\s*get\s*\{)
uses the general pattern
(?<=prefix)find(?=suffix)
EDIT
A property might have no modifier (public, private etc.) at all and the type might contain extra characters (e.g. for arrays int[,]. Therefore it would probably be better to test only for the syntax elements following the property name (and the name itself). Also a property could consist of only a setter and be abstract: abstract int[,] Matrix { set; }. I suggest retrieving the property names like this:
\w+(?=\s*\{\s*(get|set)\b)
where \b matches a word beginning or (in this case) a word end.
This may be what you are looking for and this works perfectly! I deserve some treat though :)...
Regex r=new Regex(#"(public|private).*?(?=(public|private|$))",RegexOptions.Singleline);
Regex nr=new Regex(#"\(.*?\)\s+\{",RegexOptions.Singleline);
foreach(Match m in r.Matches(yourCodeFile))//extracts all methods and properties
{
if(!nr.IsMatch(m.Value))//shoots down methods
m.Value;//properties only
}
According to this answer, try using:
for Properties: type and name:
(?:public\s|private\s|protected\s|internal\s)\s*(?:readonly|static\s+)?(?<type>\w+)\s+(?<name>\w+)[\s\r\n]*{
for Fields: type and name:
(?:public\s|private\s|protected\s)\s*(?:readonly|static\s+)?(?<type>\w+)\s+(?<name>\w+);
for Methods: methodName and parameterType and parameter:
(?:public\s|private\s|protected\s|internal\s)?[\s\w]*\s+(?<methodName>\w+)\s*\(\s*(?:(ref\s|/in\s|out\s)?\s*(?<parameterType>\w+)\s+(?<parameter>\w+)\s*,?\s*)+\)
for c# code analysis try Irony or The Roslyn Project, see this sample:
C# and VB.NET Code Searcher - Using Roslyn codeproject
Shamed by this simple question. For some reason, I want to put all asp.net URLs in an enum. But I got an error: identifer expected
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Admin.Code
{
public enum url
{
/_layouts/Admin/test1.aspx,
/_layouts/Admin/test2.aspx,
/_layouts/Admin/test3.aspx
}
class AdminUrlSettings
{
}
}
Thanks.
Here's something I've done many times to turn enumerated values into "friendly strings". You can also use it to create "string-valued" enums. It's in the same vein as Msonic's solution, but the attribute is built into the Framework.
public enum url
{
[Description(#"/_layouts/Admin/test1.aspx")] Test1,
[Description(#"/_layouts/Admin/test2.aspx")] Test2,
[Description(#"/_layouts/Admin/test2.aspx")] Test3
}
...
public static string GetDescription(this Enum enumValue)
{
object[] attr = enumValue.GetType().GetField(enumValue.ToString())
.GetCustomAttributes(typeof (DescriptionAttribute), false);
if (attr.Length > 0)
return ((DescriptionAttribute) attr[0]).Description;
return enumValue.ToString();
}
//usage
Response.Redirect(url.Test1.GetDescription());
These aren't valid enum identifiers. You'll need string enumerations. Here's an example
You will be able to do something like this:
public enum url
{
[StringValue("/_layouts/Admin/test1.aspx")]
Test1,
[StringValue("/_layouts/Admin/test2.aspx")]
Test2,
[StringValue("/_layouts/Admin/test3.aspx")]
Test3
}
Identifiers in C# can't contain / characters. They are limited to underscores, letters and numbers (and possibly a # prefix). To fix this you need to make the enum values valid C# identifiers
enum url {
test1,
test2,
test3
}
Later turning these into an actual valid url can be done with a switch statement over the value
public static string GetRelativeUrl(url u) {
switch (u) {
case url.test1:
return "/_layouts/Admin/test1.aspx";
case url.test2:
return "/_layouts/Admin/test2.aspx";
case url.test3:
return "/_layouts/Admin/test3.aspx";
default:
// Handle bad URL, possibly throw
throw new Exception();
}
}
Enums don't really work like that. Valid identifiers work the same way variable names do (ie. a combination of letters, numbers and underscores not beginning with a number). Why not just use a list:
List<string> urls = new List<string>{"/_layouts/Admin/test1.aspx", "/_layouts/Admin/test2.aspx", "/_layouts/Admin/test3.aspx"}
or use slightly different identifiers:
public enum url
{
layout_Admin_test1,
layout_Admin_test2,
layout_Admin_test3
}
Is there any way to put spaces in a C# enum constant? I've read that you can do it in VB by doing this:
Public Enum EnumWithSpaces
ConstantWithoutSpaces
[Constant With Spaces]
End Enum
...and then access it like this:
Public Sub UsingEnumWithSpaces()
Dim foo As EnumWithSpaces = EnumWithSpaces.[Constant With Spaces]
End Sub
That implies to me that the CLR can handle an enum with spaces.
Is there any way to do this in C#?
This blog post might help you:
http://blog.spontaneouspublicity.com/2008/01/17/associating-strings-with-enums-in-c/
From the article:
But enums can't have spaces in C#!"
you say. Well, I like to use the
System.ComponentModel.DescriptionAttribute
to add a more friendly description to
the enum values. The example enum can
be rewritten like this:
public enum States
{
California,
[Description("New Mexico")]
NewMexico,
[Description("New York")]
NewYork,
[Description("South Carolina")]
SouthCarolina,
Tennessee,
Washington
}
Notice that I do not put descriptions on items where the ToString() version of that item displays just fine.
CLR can handle absolutely any character in identifiers. However, C# restricts the identifier characters to those legal under the CLS, which space isn't. Same goes for VB.NET, by the way - spaces inside square brackets used to work in VB6, but they don't in VB.NET.
If you're working with Visual C# 3.0 or above I've found it convenient to just extend the enum class and use a regex to inset spaces where neccessary:
public static class EnumExtension
{
public static String ToDisplayString(this Enum e)
{
Regex regex = new Regex(#"([^\^])([A-Z][a-z$])");
return regex.Replace(e.ToString(), new MatchEvaluator(m =>
{
return String.Format("{0} {1}", m.Groups[1].Value, m.Groups[2].Value);
}));
}
}
Notice this allows you to work with any enum as is without adding descriptions to every value.
String enumWithSpaces = MessageBoxButtons.OKCancel.ToDisplayString();