handle escape (#) character in xamarin xaml [duplicate] - c#

I use this
#"^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$"
regexp to validate the email
([\w\.\-]+) - this is for the first-level domain (many letters and numbers, also point and hyphen)
([\w\-]+) - this is for second-level domain
((\.(\w){2,3})+) - and this is for other level domains(from 3 to infinity) which includes a point and 2 or 3 literals
what's wrong with this regex?
EDIT:it doesn't match the "something#someth.ing" email

TLD's like .museum aren't matched this way, and there are a few other long TLD's. Also, you can validate email addresses using the MailAddress class as Microsoft explains here in a note:
Instead of using a regular expression to validate an email address,
you can use the System.Net.Mail.MailAddress class. To determine
whether an email address is valid, pass the email address to the
MailAddress.MailAddress(String) class constructor.
public bool IsValid(string emailaddress)
{
try
{
MailAddress m = new MailAddress(emailaddress);
return true;
}
catch (FormatException)
{
return false;
}
}
This saves you a lot af headaches because you don't have to write (or try to understand someone else's) regex.
EDIT: For those who are allergic to try/catch: In .NET 5 you can use MailAddress.TryCreate. See also https://stackoverflow.com/a/68198658, including an example how to fix .., spaces, missing .TLD, etc.

I think #"^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$" should work.
You need to write it like
string email = txtemail.Text;
Regex regex = new Regex(#"^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$");
Match match = regex.Match(email);
if (match.Success)
Response.Write(email + " is correct");
else
Response.Write(email + " is incorrect");
Be warned that this will fail if:
There is a subdomain after the # symbol.
You use a TLD with a length greater than 3, such as .info

I have an expression for checking email addresses that I use.
Since none of the above were as short or as accurate as mine, I thought I would post it here.
#"^[\w!#$%&'*+\-/=?\^_`{|}~]+(\.[\w!#$%&'*+\-/=?\^_`{|}~]+)*"
+ "#"
+ #"((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3}))$";
For more info go read about it here: C# – Email Regular Expression
Also, this checks for RFC validity based on email syntax, not for whether the email really exists. The only way to test that an email really exists is to send and email and have the user verify they received the email by clicking a link or entering a token.
Then there are throw-away domains, such as Mailinator.com, and such. This doesn't do anything to verify whether an email is from a throwaway domain or not.

I found nice document on MSDN for it.
How to: Verify that Strings Are in Valid Email Format
http://msdn.microsoft.com/en-us/library/01escwtf.aspx
(check out that this code also supports the use of non-ASCII characters for Internet domain names.)
There are 2 implementation, for .Net 2.0/3.0 and for .Net 3.5 and higher.
the 2.0/3.0 version is:
bool IsValidEmail(string strIn)
{
// Return true if strIn is in valid e-mail format.
return Regex.IsMatch(strIn, #"^([\w-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
}
My tests over this method give:
Invalid: #majjf.com
Invalid: A#b#c#example.com
Invalid: Abc.example.com
Valid: j..s#proseware.com
Valid: j.#server1.proseware.com
Invalid: js*#proseware.com
Invalid: js#proseware..com
Valid: ma...ma#jjf.co
Valid: ma.#jjf.com
Invalid: ma##jjf.com
Invalid: ma#jjf.
Invalid: ma#jjf..com
Invalid: ma#jjf.c
Invalid: ma_#jjf
Invalid: ma_#jjf.
Valid: ma_#jjf.com
Invalid: -------
Valid: 12#hostname.com
Valid: d.j#server1.proseware.com
Valid: david.jones#proseware.com
Valid: j.s#server1.proseware.com
Invalid: j#proseware.com9
Valid: j_9#[129.126.118.1]
Valid: jones#ms1.proseware.com
Invalid: js#internal#proseware.com
Invalid: js#proseware.com9
Invalid: js#proseware.com9
Valid: m.a#hostname.co
Valid: m_a1a#hostname.com
Valid: ma.h.saraf.onemore#hostname.com.edu
Valid: ma#hostname.com
Invalid: ma#hostname.comcom
Invalid: MA#hostname.coMCom
Valid: ma12#hostname.com
Valid: ma-a.aa#hostname.com.edu
Valid: ma-a#hostname.com
Valid: ma-a#hostname.com.edu
Valid: ma-a#1hostname.com
Valid: ma.a#1hostname.com
Valid: ma#1hostname.com

The following code is based on Microsoft's Data annotations implementation on github and I think it's the most complete validation for emails:
public static Regex EmailValidation()
{
const string pattern = #"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))#((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$";
const RegexOptions options = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture;
// Set explicit regex match timeout, sufficient enough for email parsing
// Unless the global REGEX_DEFAULT_MATCH_TIMEOUT is already set
TimeSpan matchTimeout = TimeSpan.FromSeconds(2);
try
{
if (AppDomain.CurrentDomain.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") == null)
{
return new Regex(pattern, options, matchTimeout);
}
}
catch
{
// Fallback on error
}
// Legacy fallback (without explicit match timeout)
return new Regex(pattern, options);
}

This does not meet all of the requirements of RFCs 5321 and 5322, but it works with the following definitions.
#"^([0-9a-zA-Z]([\+\-_\.][0-9a-zA-Z]+)*)+"#(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]*\.)+[a-zA-Z0-9]{2,17})$";
Below is the code
const String pattern =
#"^([0-9a-zA-Z]" + //Start with a digit or alphabetical
#"([\+\-_\.][0-9a-zA-Z]+)*" + // No continuous or ending +-_. chars in email
#")+" +
#"#(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]*\.)+[a-zA-Z0-9]{2,17})$";
var validEmails = new[] {
"ma#hostname.com",
"ma#hostname.comcom",
"MA#hostname.coMCom",
"m.a#hostname.co",
"m_a1a#hostname.com",
"ma-a#hostname.com",
"ma-a#hostname.com.edu",
"ma-a.aa#hostname.com.edu",
"ma.h.saraf.onemore#hostname.com.edu",
"ma12#hostname.com",
"12#hostname.com",
};
var invalidEmails = new[] {
"Abc.example.com", // No `#`
"A#b#c#example.com", // multiple `#`
"ma...ma#jjf.co", // continuous multiple dots in name
"ma#jjf.c", // only 1 char in extension
"ma#jjf..com", // continuous multiple dots in domain
"ma##jjf.com", // continuous multiple `#`
"#majjf.com", // nothing before `#`
"ma.#jjf.com", // nothing after `.`
"ma_#jjf.com", // nothing after `_`
"ma_#jjf", // no domain extension
"ma_#jjf.", // nothing after `_` and .
"ma#jjf.", // nothing after `.`
};
foreach (var str in validEmails)
{
Console.WriteLine("{0} - {1} ", str, Regex.IsMatch(str, pattern));
}
foreach (var str in invalidEmails)
{
Console.WriteLine("{0} - {1} ", str, Regex.IsMatch(str, pattern));
}

Best email validation regex
[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
And it's usage :-
bool isEmail = Regex.IsMatch(emailString, #"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z", RegexOptions.IgnoreCase);

new System.ComponentModel.DataAnnotations.EmailAddressAttribute().IsValid(input)

As an update to the popular answer of Alex: In .NET 5 MailAddress now has a TryCreate. So you can do something like:
public static bool IsValidEmail(string email)
{
if (!MailAddress.TryCreate(email, out var mailAddress))
return false;
// And if you want to be more strict:
var hostParts = mailAddress.Host.Split('.');
if (hostParts.Length == 1)
return false; // No dot.
if (hostParts.Any(p => p == string.Empty))
return false; // Double dot.
if (hostParts[^1].Length < 2)
return false; // TLD only one letter.
if (mailAddress.User.Contains(' '))
return false;
if (mailAddress.User.Split('.').Any(p => p == string.Empty))
return false; // Double dot or dot at end of user part.
return true;
}

Why not use EF6 attribute based e-mail validation?
As you can see above, Regex validation for e-mail always has some hole in it. If you are using EF6 data annotations, you can easily achieve reliable and stronger e-mail validation with EmailAddress data annotation attribute available for that. I had to remove the regex validation I used before for e-mail when I got mobile device specific regex failure on e-mail input field. When the data annotation attribute used for e-mail validation, the issue on mobile was resolved.
public class LoginViewModel
{
[EmailAddress(ErrorMessage = "The email format is not valid")]
public string Email{ get; set; }

Try this on for size:
public static bool IsValidEmailAddress(this string s)
{
var regex = new Regex(#"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?");
return regex.IsMatch(s);
}

This regex works perfectly:
bool IsValidEmail(string email)
{
return Regex.IsMatch(email, #"^[\w!#$%&'*+\-/=?\^_`{|}~]+(\.[\w!#$%&'*+\-/=?\^_`{|}~]+)*#((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3}))\z");
}

Email validation using regex
string pattern = #"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z";
//check first string
if (Regex.IsMatch(EmailId1 , pattern))
{
//if email is valid
Console.WriteLine(EmailId1+ " is a valid Email address ");
}
Source: email validation c#
Validation Without Regex using MailAddress.MailAddress(String) class constructor
public bool IsEmailValid(string emailaddress)
{
try
{
MailAddress m = new MailAddress(emailaddress);
return true;
}
catch (FormatException)
{
return false;
}
}

This one prevents invalid emails mentioned by others in the comments:
Abc.#example.com
Abc..123#example.com
name#hotmail
toms.email.#gmail.com
test#-online.com
It also prevents emails with double dots:
hello..world#example..com
Try testing it with as many invalid email addresses as you can find.
using System.Text.RegularExpressions;
public static bool IsValidEmail(string email)
{
return Regex.IsMatch(email, #"\A[a-z0-9]+([-._][a-z0-9]+)*#([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,4}\z")
&& Regex.IsMatch(email, #"^(?=.{1,64}#.{4,64}$)(?=.{6,100}$).*");
}
See validate email address using regular expression in C#.

Try this, it's working for me:
public bool IsValidEmailAddress(string s)
{
if (string.IsNullOrEmpty(s))
return false;
else
{
var regex = new Regex(#"\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*");
return regex.IsMatch(s) && !s.EndsWith(".");
}
}

To validate your email ID, you can simply create such method and use it.
public static bool IsValidEmail(string email)
{
var r = new Regex(#"^([0-9a-zA-Z]([-\.\w]*[0-9a-zA-Z])*#([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$");
return !String.IsNullOrEmpty(email) && r.IsMatch(email);
}
This will return True / False. (Valid / Invalid Email Id)

It has taken many attempts to create an email validator which catches nearly all worldwide requirements for email.
Extension method you can call with:
myEmailString.IsValidEmailAddress();
Regex pattern string you can get by calling:
var myPattern = Regex.EmailPattern;
The Code (mostly comments):
/// <summary>
/// Validates the string is an Email Address...
/// </summary>
/// <param name="emailAddress"></param>
/// <returns>bool</returns>
public static bool IsValidEmailAddress(this string emailAddress)
{
var valid = true;
var isnotblank = false;
var email = emailAddress.Trim();
if (email.Length > 0)
{
// Email Address Cannot start with period.
// Name portion must be at least one character
// In the Name, valid characters are: a-z 0-9 ! # _ % & ' " = ` { } ~ - + * ? ^ | / $
// Cannot have period immediately before # sign.
// Cannot have two # symbols
// In the domain, valid characters are: a-z 0-9 - .
// Domain cannot start with a period or dash
// Domain name must be 2 characters.. not more than 256 characters
// Domain cannot end with a period or dash.
// Domain must contain a period
isnotblank = true;
valid = Regex.IsMatch(email, Regex.EmailPattern, RegexOptions.IgnoreCase) &&
!email.StartsWith("-") &&
!email.StartsWith(".") &&
!email.EndsWith(".") &&
!email.Contains("..") &&
!email.Contains(".#") &&
!email.Contains("#.");
}
return (valid && isnotblank);
}
/// <summary>
/// Validates the string is an Email Address or a delimited string of email addresses...
/// </summary>
/// <param name="emailAddress"></param>
/// <returns>bool</returns>
public static bool IsValidEmailAddressDelimitedList(this string emailAddress, char delimiter = ';')
{
var valid = true;
var isnotblank = false;
string[] emails = emailAddress.Split(delimiter);
foreach (string e in emails)
{
var email = e.Trim();
if (email.Length > 0 && valid) // if valid == false, no reason to continue checking
{
isnotblank = true;
if (!email.IsValidEmailAddress())
{
valid = false;
}
}
}
return (valid && isnotblank);
}
public class Regex
{
/// <summary>
/// Set of Unicode Characters currently supported in the application for email, etc.
/// </summary>
public static readonly string UnicodeCharacters = "À-ÿ\p{L}\p{M}ÀàÂâÆæÇçÈèÉéÊêËëÎîÏïÔôŒœÙùÛûÜü«»€₣äÄöÖüÜß"; // German and French
/// <summary>
/// Set of Symbol Characters currently supported in the application for email, etc.
/// Needed if a client side validator is being used.
/// Not needed if validation is done server side.
/// The difference is due to subtle differences in Regex engines.
/// </summary>
public static readonly string SymbolCharacters = #"!#%&'""=`{}~\.\-\+\*\?\^\|\/\$";
/// <summary>
/// Regular Expression string pattern used to match an email address.
/// The following characters will be supported anywhere in the email address:
/// ÀàÂâÆæÇçÈèÉéÊêËëÎîÏïÔôŒœÙùÛûÜü«»€₣äÄöÖüÜß[a - z][A - Z][0 - 9] _
/// The following symbols will be supported in the first part of the email address(before the # symbol):
/// !#%&'"=`{}~.-+*?^|\/$
/// Emails cannot start or end with periods,dashes or #.
/// Emails cannot have two # symbols.
/// Emails must have an # symbol followed later by a period.
/// Emails cannot have a period before or after the # symbol.
/// </summary>
public static readonly string EmailPattern = String.Format(
#"^([\w{0}{2}])+#{1}[\w{0}]+([-.][\w{0}]+)*\.[\w{0}]+([-.][\w{0}]+)*$", // #"^[{0}\w]+([-+.'][{0}\w]+)*#[{0}\w]+([-.][{0}\w]+)*\.[{0}\w]+([-.][{0}\w]+)*$",
UnicodeCharacters,
"{1}",
SymbolCharacters
);
}

public static bool ValidateEmail(string str)
{
return Regex.IsMatch(str, #"\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*");
}
I use the above code to validate the email address.

public bool VailidateEntriesForAccount()
{
if (!(txtMailId.Text.Trim() == string.Empty))
{
if (!IsEmail(txtMailId.Text))
{
Logger.Debug("Entered invalid Email ID's");
MessageBox.Show("Please enter valid Email Id's" );
txtMailId.Focus();
return false;
}
}
}
private bool IsEmail(string strEmail)
{
Regex validateEmail = new Regex("^[\\W]*([\\w+\\-.%]+#[\\w\\-.]+\\.[A-Za-z] {2,4}[\\W]*,{1}[\\W]*)*([\\w+\\-.%]+#[\\w\\-.]+\\.[A-Za-z]{2,4})[\\W]*$");
return validateEmail.IsMatch(strEmail);
}

This is my favorite approach to this so far:
public static class CommonExtensions
{
public static bool IsValidEmail(this string thisEmail)
=> !string.IsNullOrWhiteSpace(thisEmail) &&
new Regex(#"^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$").IsMatch(thisEmail);
}
Then use the created string extension like:
if (!emailAsString.IsValidEmail()) throw new Exception("Invalid Email");

There's no perfect regular expression, but this one is pretty strong, I think, based on study of RFC5322. And with C# string interpolation, pretty easy to follow, I think, as well.
const string atext = #"a-zA-Z\d!#\$%&'\*\+-/=\?\^_`\{\|\}~";
var localPart = $"[{atext}]+(\\.[{atext}]+)*";
var domain = $"[{atext}]+(\\.[{atext}]+)*";
Assert.That(() => EmailRegex = new Regex($"^{localPart}#{domain}$", Compiled),
Throws.Nothing);
Vetted with NUnit 2.x.

Just let me know IF it doesn't work :)
public static bool isValidEmail(this string email)
{
string[] mail = email.Split(new string[] { "#" }, StringSplitOptions.None);
if (mail.Length != 2)
return false;
//check part before ...#
if (mail[0].Length < 1)
return false;
System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(#"^[a-zA-Z0-9_\-\.]+$");
if (!regex.IsMatch(mail[0]))
return false;
//check part after #...
string[] domain = mail[1].Split(new string[] { "." }, StringSplitOptions.None);
if (domain.Length < 2)
return false;
regex = new System.Text.RegularExpressions.Regex(#"^[a-zA-Z0-9_\-]+$");
foreach (string d in domain)
{
if (!regex.IsMatch(d))
return false;
}
//get TLD
if (domain[domain.Length - 1].Length < 2)
return false;
return true;
}

I've created a FormValidationUtils class to validate email:
public static class FormValidationUtils
{
const string ValidEmailAddressPattern = "^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,6}$";
public static bool IsEmailValid(string email)
{
var regex = new Regex(ValidEmailAddressPattern, RegexOptions.IgnoreCase);
return regex.IsMatch(email);
}
}

Try the Following Code:
using System.Text.RegularExpressions;
if (!Regex.IsMatch(txtEmail.Text, #"^[a-z,A-Z]{1,10}((-|.)\w+)*#\w+.\w{3}$"))
MessageBox.Show("Not valid email.");

STRING SEARCH USING REGEX METHOD IN C#
How to validate an Email by Regular Expression?
string EmailPattern = #"\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*";
if (Regex.IsMatch(Email, EmailPattern, RegexOptions.IgnoreCase))
{
Console.WriteLine("Email: {0} is valid.", Email);
}
else
{
Console.WriteLine("Email: {0} is not valid.", Email);
}
Use Reference String.Regex() Method

string patternEmail = #"(?<email>\w+#\w+\.[a-z]{0,3})";
Regex regexEmail = new Regex(patternEmail);

1
^[\w!#$%&'*+\-/=?\^_`{|}~]+(\.[\w!#$%&'*+\-/=?\^_`{|}~]+)*#((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3}))$
2
^(([^<>()[\]\\.,;:\s#\""]+(\.[^<>()[\]\\.,;:\s#\""]+)*)|(\"".+\""))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$

I think your caret and dollar sign are part of the problem
You should also modify the regex a little, I use the next
#"[ :]+([\w.-]+)#([\w-.])+((.(\w){2,3})+)"

Regex Email Pattern:
^(?:[\\w\\!\\#\\$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\`\\{\\|\\}\\~]+\\.)*[\\w\\!\\#\\$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\`\\{\\|\\}\\~]+#(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-](?!\\.)){0,61}[a-zA-Z0-9]?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\\[(?:(?:[01]?\\d{1,2}|2[0-4]\\d|25[0-5])\\.){3}(?:[01]?\\d{1,2}|2[0-4]\\d|25[0-5])\\]))$

I've been using the Regex.IsMatch().
First of all you need to add the next statement:
using System.Text.RegularExpressions;
Then the method looks like:
private bool EmailValidation(string pEmail)
{
return Regex.IsMatch(pEmail,
#"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))" +
#"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$",
RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
}
It's a private method because of my logic but you can put the method as static in another Layer such as "Utilities" and call it from where you need.

Related

To check if an element is present in a string array using "Regex" in c#

Help me guys to complete the code using Regex. I'm new to learn c#.
Create a C# program to complete the following task using Regular Expressions
i. Create a string variable 'Myinput' and read the value from user
ii. Check whether the given values are matching with the following
Cappuccino
Tea
Milk
Espresso
iii. If any other values except the above, the program need to throw an error
message
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace RegularExpression
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter the user choice input");
string Myinput = Console.ReadLine();
string[] arrayy = new string[4] { "Cappucino", "Tea", "Milk", "Espresso" };
MyChoice obj = new MyChoice();
bool ans = obj.MyChoiceContains(Myinput, arrayy);
Console.WriteLine(ans);
Console.ReadKey();
/// i. Create a string variable 'Myinput' and read the value from user.
/// ii. Check whether the given values are matching with the following
/// 1.Cappuccino 2. Tea 3. Milk 4. Espresso.
/// iii. If any other values except the above, the program need to throw the error
///message.
/// Display valid or invalid message here.
}
}
public class MyChoice
{
public bool MyChoiceContains(string Userchoice, string[] myChoiceValues)
{
Userchoice = #"^[A-Za-z]$";
Regex rg = new Regex(Userchoice);
bool ans = true;
foreach (string s in myChoiceValues)
{
ans = Regex.IsMatch(Userchoice, s);
}
return ans;
}
}
}
/// <summary>
/// Create Class with Class name 'MyChoice'.
/// </summary>
/// <summary>
/// Create a method with the name 'MyChoiceContains'.
/// <param name="Userchoice"></param><type>string</type>
/// <param name="myChoiceValues"></param><type>string[]</type>
/// <returns>bool</returns>return "true" if valid else return "false".
/// Note: Please dont use Console.WriteLine() and Console.ReadLine() in this method.
/// </summary>
In the comments you have stated that the user will input a regular expression, and that you want to check if the regular expression matches on any of the elements in the array. You can either do this manually:
foreach (string s in myChoiceValues)
{
if (rg.IsMatch(s))
return true;
}
return false;
I've moved the return false; outside so that you don't return false; when the first item doesn't match.
Alternatively, you can do this using the LINQ extension methods. You'll need to ensure you have using System.Linq; at the top of your file.
return myChoiceValues.Any(v => rg.IsMatch(v));
// or simply: return myChoiceValues.Any(rg.IsMatch);
You might also need to rewrite your hardcoded test expression (^[A-Za-z]$) as this currently requires a single character between the start and end of the string (i.e. the matched string should be a single character). Perhaps you meant:
^[A-Za-z]+$
The + means it will match 1 or more characters matching from the [A-Za-z] set.
string pattern = #"(Cappuccino | Tea | Milk | Espresso)";
string input = "text";
Match m = Regex.Match(input, pattern, RegexOptions.IgnoreCase);
if (m.Success)
{
// matched
}
else
{
// not matched
}
Ressource

How to check a text contains a certain character within selenium

I have a method below where I retrieve a HTML tag:
public void CheckEmailDisplayed()
{
var email = _driver.FindElement(ConfirmationResponsiveElements.ViewEmail);
}
ViewEmail is below:
public static By ViewEmail => By.ClassName("confirmation-banner__text");
The HTML it corresponds to is:
<div class="confirmation-banner__text firefinder-match">
<p>
We've sent an email to
<strong>firstname#xxx.com</strong>
</p>
<p>
</div>
What I want to do is be able to use the variable email to check that the text contains an #. This is to help determine an email address is displayed. How can this be achieved?
Thanks
Option 1: Check for the # symbol
string email = "test#domain.com";
if (email.Contains("#"))
{
// code here
}
Option 2: Validate Email Address
public static bool IsEmail(string emailToValidate)
{
if (string.IsNullOrEmpty(emailToValidate)) return true;
return Regex.IsMatch(emailToValidate, #"^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
}
How to use option 2:
string email = "test#domain.com";
if (IsEmail(email))
{
// valid email address
}
else
{
// not a valid email address
}
You can add another definition
public static By ViewEmailAddress => By.TagName("strong");
Then use
var emailAddress = emai.FindElement(ConfirmationResponsiveElements.ViewEmailAddress);
var emailAddressText = emailAddress.Text;
And then you can do different operations that you want on emailAddressText. Like validating it having # or doing more complex validations like a email pattern check
You can use IndexOf method
bool found = Value1.IndexOf("abc", 0, 7) != -1;
OR
You can also use regular expressions (less readable though)
string regex = "^.{0,7}abc";
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(regex);
string Value1 = "sssddabcgghh";
Console.WriteLine(reg.Match(Value1).Success);
Source :-
How to determine if string contains specific substring within the first X characters

How to write a data annotation to check if email address found in string and fail on it

I have the following code but it's not quite working... Any ideas where i'm going wrong? It seems to be failing when there is a carriage return in the string? (see fiddles at bottom)
[RegularExpression(#"^((?!([\w!#$%&'*+\-/=?\^_`{|}~]+(\.[\w!#$%&'*+\-/=?\^_`{|}~]+)*#((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3})))).)*$", ErrorMessage = "Please do not include an email address in your description.")]
Context
People are writing descriptions and also placing email addresses in them, for example:
"Hi there i'm bob, here is my email: example#exampele.com. Hope you
havea great day at my party."
I need to check that string and see that there is an email, and then not allow it to be submitted. (I'm using Entity framework and data annotations alongside the jquery validation in ASP .NET MVC 5... This is why i mentioned Data annotation usage.
Note:
I took the inversion technique from here:
Jquery validation on matching 'password' and 'admin' not working
And the email validation from here:
Best Regular Expression for Email Validation in C#
Attempts:
The following string:
http://pastebin.com/00BE7tUW
will show the error, whereas this will not:
http://pastebin.com/i69uxzRf
So something is a little wrong in the expression considering there is no email in it?
Fiddle:
Not working: https://regex101.com/r/zL7xD7/1
Working: https://regex101.com/r/hJ8fJ9/1
Working with email: https://regex101.com/r/dB3cU2/1
Have you tried something like this:
bool invalid = false;
public bool IsValidEmail(string strIn)
{
invalid = false;
if (String.IsNullOrEmpty(strIn))
return false;
// Use IdnMapping class to convert Unicode domain names.
try {
strIn = Regex.Replace(strIn, #"(#)(.+)$", this.DomainMapper,
RegexOptions.None, TimeSpan.FromMilliseconds(200));
}
catch (RegexMatchTimeoutException) {
return false;
}
if (invalid)
return false;
// Return true if strIn is in valid e-mail format.
try {
return Regex.IsMatch(strIn,
#"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))" +
#"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$",
RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
}
catch (RegexMatchTimeoutException) {
return false;
}
}
private string DomainMapper(Match match)
{
// IdnMapping class with default property values.
IdnMapping idn = new IdnMapping();
string domainName = match.Groups[2].Value;
try {
domainName = idn.GetAscii(domainName);
}
catch (ArgumentException) {
invalid = true;
}
return match.Groups[1].Value + domainName;
}
The IsValidEmail method returns true if the string contains a valid email address and false if it does not, but takes no other action.
To verify that the email address is valid, the IsValidEmail method calls the Regex.Replace(String, String, MatchEvaluator) method with the (#)(.+)$ regular expression pattern to separate the domain name from the email address. The third parameter is a MatchEvaluator delegate that represents the method that processes and replaces the matched text.
Then you would check the email address by doing something like:
IsValidEmail(emailAddress)
Does this work for you?
The . needed to be replaced by [\S\s]
[RegularExpression(#"^((?!([\w!#$%&'*+\-/=?\^_`{|}~]+(\.[\w!#$%&'*+\-/=?\^_`{|}~]+)*#((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3}))))[\S\s])*$", ErrorMessage = "Please do not include an email address in your field description.")]
source: Regular expression is not matching new lines

Regex to validate a semi-colon seperated list of emails?

I have the following c# extension method for validating an email address. The regex came from Microsoft on their How to: Verify that Strings Are in Valid Email Format page.
I need to improve this method to be able to handle a semi-colon seperated list of emails. An valid example string could be as badly formatted as: ";; ; ; xxx.sss.xxx ; ;; xxx.sss.xxx;"
/// <summary>
/// Validates the string is an Email Address...
/// </summary>
/// <param name="emailAddress"></param>
/// <returns>bool</returns>
public static bool IsValidEmailAddress(this string emailAddress)
{
var valid = true;
var isnotblank = false;
var email = emailAddress.Trim();
if (email.Length > 0)
{
isnotblank = true;
valid = Regex.IsMatch(email, #"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))" +
#"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$", RegexOptions.IgnoreCase);
}
return (valid && isnotblank);
}
Microsoft's regex does a pretty good job. However, it doesn't catch a few strange scenarios and a number of special characters which are valid for email. I'll give you a different regex. Choose to use it or not is your prerogative.
I would separate the concerns by having one extension method which validates an email address and another which validates the list. Do a .trim() on each email before passing it to the email validation method. So, something like this:
/// <summary>
/// Validates the string is an Email Address...
/// </summary>
/// <param name="emailAddress"></param>
/// <returns>bool</returns>
public static bool IsValidEmailAddress(this string emailAddress)
{
var valid = true;
var isnotblank = false;
var email = emailAddress.Trim();
if (email.Length > 0)
{
// Email Address Cannot start with period.
// Name portion must be at least one character
// In the Name, valid characters are: a-z 0-9 ! # _ % & ' " = ` { } ~ - + * ? ^ | / $
// Cannot have period immediately before # sign.
// Cannot have two # symbols
// In the domain, valid characters are: a-z 0-9 - .
// Domain cannot start with a period or dash
// Domain name must be 2 characters.. not more than 256 characters
// Domain cannot end with a period or dash.
// Domain must contain a period
isnotblank = true;
valid = Regex.IsMatch(email, #"\A([\w!#%&'""=`{}~\.\-\+\*\?\^\|\/\$])+#{1}\w+([-.]\w+)*\.\w+([-.]\w+)*\z", RegexOptions.IgnoreCase) &&
!email.StartsWith("-") &&
!email.StartsWith(".") &&
!email.EndsWith(".") &&
!email.Contains("..") &&
!email.Contains(".#") &&
!email.Contains("#.");
}
return (valid && isnotblank);
}
/// <summary>
/// Validates the string is an Email Address or a delimited string of email addresses...
/// </summary>
/// <param name="emailAddress"></param>
/// <returns>bool</returns>
public static bool IsValidEmailAddressDelimitedList(this string emailAddress, char delimiter = ';')
{
var valid = true;
var isnotblank = false;
string[] emails = emailAddress.Split(delimiter);
foreach (string e in emails)
{
var email = e.Trim();
if (email.Length > 0 && valid) // if valid == false, no reason to continue checking
{
isnotblank = true;
if (!email.IsValidEmailAddress())
{
valid = false;
}
}
}
return (valid && isnotblank);
}
You can use the following regex to allow several emails separated by semicolon and (optionally) spaces besides the semicolon. It will also accept single email address that does not end in semicolon.
Right now it allows empty entries as well(no email addresses). If You wanna change it to have at least 1, then replace the final * by + to require at least one address.
(([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)(\s*;\s*|\s*$))*
If you want to allow comma as well as semicolon, you can chage following :
(\s*;\s*|\s*$)
to this:
(\s*(;|,)\s*|\s*$)

How do I check if a given string is a legal/valid file name under Windows?

I want to include a batch file rename functionality in my application. A user can type a destination filename pattern and (after replacing some wildcards in the pattern) I need to check if it's going to be a legal filename under Windows. I've tried to use regular expression like [a-zA-Z0-9_]+ but it doesn't include many national-specific characters from various languages (e.g. umlauts and so on). What is the best way to do such a check?
From MSDN's "Naming a File or Directory," here are the general conventions for what a legal file name is under Windows:
You may use any character in the current code page (Unicode/ANSI above 127), except:
< > : " / \ | ? *
Characters whose integer representations are 0-31 (less than ASCII space)
Any other character that the target file system does not allow (say, trailing periods or spaces)
Any of the DOS names: CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9 (and avoid AUX.txt, etc)
The file name is all periods
Some optional things to check:
File paths (including the file name) may not have more than 260 characters (that don't use the \?\ prefix)
Unicode file paths (including the file name) with more than 32,000 characters when using \?\ (note that prefix may expand directory components and cause it to overflow the 32,000 limit)
You can get a list of invalid characters from Path.GetInvalidPathChars and GetInvalidFileNameChars.
UPD: See Steve Cooper's suggestion on how to use these in a regular expression.
UPD2: Note that according to the Remarks section in MSDN "The array returned from this method is not guaranteed to contain the complete set of characters that are invalid in file and directory names." The answer provided by sixlettervaliables goes into more details.
For .Net Frameworks prior to 3.5 this should work:
Regular expression matching should get you some of the way. Here's a snippet using the System.IO.Path.InvalidPathChars constant;
bool IsValidFilename(string testName)
{
Regex containsABadCharacter = new Regex("["
+ Regex.Escape(System.IO.Path.InvalidPathChars) + "]");
if (containsABadCharacter.IsMatch(testName)) { return false; };
// other checks for UNC, drive-path format, etc
return true;
}
For .Net Frameworks after 3.0 this should work:
http://msdn.microsoft.com/en-us/library/system.io.path.getinvalidpathchars(v=vs.90).aspx
Regular expression matching should get you some of the way. Here's a snippet using the System.IO.Path.GetInvalidPathChars() constant;
bool IsValidFilename(string testName)
{
Regex containsABadCharacter = new Regex("["
+ Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]");
if (containsABadCharacter.IsMatch(testName)) { return false; };
// other checks for UNC, drive-path format, etc
return true;
}
Once you know that, you should also check for different formats, eg c:\my\drive and \\server\share\dir\file.ext
Try to use it, and trap for the error. The allowed set may change across file systems, or across different versions of Windows. In other words, if you want know if Windows likes the name, hand it the name and let it tell you.
This class cleans filenames and paths; use it like
var myCleanPath = PathSanitizer.SanitizeFilename(myBadPath, ' ');
Here's the code;
/// <summary>
/// Cleans paths of invalid characters.
/// </summary>
public static class PathSanitizer
{
/// <summary>
/// The set of invalid filename characters, kept sorted for fast binary search
/// </summary>
private readonly static char[] invalidFilenameChars;
/// <summary>
/// The set of invalid path characters, kept sorted for fast binary search
/// </summary>
private readonly static char[] invalidPathChars;
static PathSanitizer()
{
// set up the two arrays -- sorted once for speed.
invalidFilenameChars = System.IO.Path.GetInvalidFileNameChars();
invalidPathChars = System.IO.Path.GetInvalidPathChars();
Array.Sort(invalidFilenameChars);
Array.Sort(invalidPathChars);
}
/// <summary>
/// Cleans a filename of invalid characters
/// </summary>
/// <param name="input">the string to clean</param>
/// <param name="errorChar">the character which replaces bad characters</param>
/// <returns></returns>
public static string SanitizeFilename(string input, char errorChar)
{
return Sanitize(input, invalidFilenameChars, errorChar);
}
/// <summary>
/// Cleans a path of invalid characters
/// </summary>
/// <param name="input">the string to clean</param>
/// <param name="errorChar">the character which replaces bad characters</param>
/// <returns></returns>
public static string SanitizePath(string input, char errorChar)
{
return Sanitize(input, invalidPathChars, errorChar);
}
/// <summary>
/// Cleans a string of invalid characters.
/// </summary>
/// <param name="input"></param>
/// <param name="invalidChars"></param>
/// <param name="errorChar"></param>
/// <returns></returns>
private static string Sanitize(string input, char[] invalidChars, char errorChar)
{
// null always sanitizes to null
if (input == null) { return null; }
StringBuilder result = new StringBuilder();
foreach (var characterToTest in input)
{
// we binary search for the character in the invalid set. This should be lightning fast.
if (Array.BinarySearch(invalidChars, characterToTest) >= 0)
{
// we found the character in the array of
result.Append(errorChar);
}
else
{
// the character was not found in invalid, so it is valid.
result.Append(characterToTest);
}
}
// we're done.
return result.ToString();
}
}
This is what I use:
public static bool IsValidFileName(this string expression, bool platformIndependent)
{
string sPattern = #"^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"";|/]+$";
if (platformIndependent)
{
sPattern = #"^(([a-zA-Z]:|\\)\\)?(((\.)|(\.\.)|([^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?))\\)*[^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?$";
}
return (Regex.IsMatch(expression, sPattern, RegexOptions.CultureInvariant));
}
The first pattern creates a regular expression containing the invalid/illegal file names and characters for Windows platforms only. The second one does the same but ensures that the name is legal for any platform.
One corner case to keep in mind, which surprised me when I first found out about it: Windows allows leading space characters in file names! For example, the following are all legal, and distinct, file names on Windows (minus the quotes):
"file.txt"
" file.txt"
" file.txt"
One takeaway from this: Use caution when writing code that trims leading/trailing whitespace from a filename string.
Simplifying the Eugene Katz's answer:
bool IsFileNameCorrect(string fileName){
return !fileName.Any(f=>Path.GetInvalidFileNameChars().Contains(f))
}
Or
bool IsFileNameCorrect(string fileName){
return fileName.All(f=>!Path.GetInvalidFileNameChars().Contains(f))
}
Microsoft Windows: Windows kernel forbids the use of characters in range 1-31 (i.e., 0x01-0x1F) and characters " * : < > ? \ |. Although NTFS allows each path component (directory or filename) to be 255 characters long and paths up to about 32767 characters long, the Windows kernel only supports paths up to 259 characters long. Additionally, Windows forbids the use of the MS-DOS device names AUX, CLOCK$, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, NUL and PRN, as well as these names with any extension (for example, AUX.txt), except when using Long UNC paths (ex. \.\C:\nul.txt or \?\D:\aux\con). (In fact, CLOCK$ may be used if an extension is provided.) These restrictions only apply to Windows - Linux, for example, allows use of " * : < > ? \ | even in NTFS.
Source: http://en.wikipedia.org/wiki/Filename
Rather than explicitly include all possible characters, you could do a regex to check for the presence of illegal characters, and report an error then. Ideally your application should name the files exactly as the user wishes, and only cry foul if it stumbles across an error.
The question is are you trying to determine if a path name is a legal windows path, or if it's legal on the system where the code is running.? I think the latter is more important, so personally, I'd probably decompose the full path and try to use _mkdir to create the directory the file belongs in, then try to create the file.
This way you know not only if the path contains only valid windows characters, but if it actually represents a path that can be written by this process.
I use this to get rid of invalid characters in filenames without throwing exceptions:
private static readonly Regex InvalidFileRegex = new Regex(
string.Format("[{0}]", Regex.Escape(#"<>:""/\|?*")));
public static string SanitizeFileName(string fileName)
{
return InvalidFileRegex.Replace(fileName, string.Empty);
}
Also CON, PRN, AUX, NUL, COM# and a few others are never legal filenames in any directory with any extension.
To complement the other answers, here are a couple of additional edge cases that you might want to consider.
Excel can have problems if you save a workbook in a file whose name contains the '[' or ']' characters. See http://support.microsoft.com/kb/215205 for details.
Sharepoint has a whole additional set of restrictions. See http://support.microsoft.com/kb/905231 for details.
From MSDN, here's a list of characters that aren't allowed:
Use almost any character in the current code page for a name, including Unicode characters and characters in the extended character set (128–255), except for the following:
The following reserved characters are not allowed:
< > : " / \ | ? *
Characters whose integer representations are in the range from zero through 31 are not allowed.
Any other character that the target file system does not allow.
This is an already answered question, but just for the sake of "Other options", here's a non-ideal one:
(non-ideal because using Exceptions as flow control is a "Bad Thing", generally)
public static bool IsLegalFilename(string name)
{
try
{
var fileInfo = new FileInfo(name);
return true;
}
catch
{
return false;
}
}
Also the destination file system is important.
Under NTFS, some files can not be created in specific directories.
E.G. $Boot in root
Regular expressions are overkill for this situation. You can use the String.IndexOfAny() method in combination with Path.GetInvalidPathChars() and Path.GetInvalidFileNameChars().
Also note that both Path.GetInvalidXXX() methods clone an internal array and return the clone. So if you're going to be doing this a lot (thousands and thousands of times) you can cache a copy of the invalid chars array for reuse.
many of these answers will not work if the filename is too long & running on a pre Windows 10 environment. Similarly, have a think about what you want to do with periods - allowing leading or trailing is technically valid, but can create problems if you do not want the file to be difficult to see or delete respectively.
This is a validation attribute I created to check for a valid filename.
public class ValidFileNameAttribute : ValidationAttribute
{
public ValidFileNameAttribute()
{
RequireExtension = true;
ErrorMessage = "{0} is an Invalid Filename";
MaxLength = 255; //superseeded in modern windows environments
}
public override bool IsValid(object value)
{
//http://stackoverflow.com/questions/422090/in-c-sharp-check-that-filename-is-possibly-valid-not-that-it-exists
var fileName = (string)value;
if (string.IsNullOrEmpty(fileName)) { return true; }
if (fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1 ||
(!AllowHidden && fileName[0] == '.') ||
fileName[fileName.Length - 1]== '.' ||
fileName.Length > MaxLength)
{
return false;
}
string extension = Path.GetExtension(fileName);
return (!RequireExtension || extension != string.Empty)
&& (ExtensionList==null || ExtensionList.Contains(extension));
}
private const string _sepChar = ",";
private IEnumerable<string> ExtensionList { get; set; }
public bool AllowHidden { get; set; }
public bool RequireExtension { get; set; }
public int MaxLength { get; set; }
public string AllowedExtensions {
get { return string.Join(_sepChar, ExtensionList); }
set {
if (string.IsNullOrEmpty(value))
{ ExtensionList = null; }
else {
ExtensionList = value.Split(new char[] { _sepChar[0] })
.Select(s => s[0] == '.' ? s : ('.' + s))
.ToList();
}
} }
public override bool RequiresValidationContext => false;
}
and the tests
[TestMethod]
public void TestFilenameAttribute()
{
var rxa = new ValidFileNameAttribute();
Assert.IsFalse(rxa.IsValid("pptx."));
Assert.IsFalse(rxa.IsValid("pp.tx."));
Assert.IsFalse(rxa.IsValid("."));
Assert.IsFalse(rxa.IsValid(".pp.tx"));
Assert.IsFalse(rxa.IsValid(".pptx"));
Assert.IsFalse(rxa.IsValid("pptx"));
Assert.IsFalse(rxa.IsValid("a/abc.pptx"));
Assert.IsFalse(rxa.IsValid("a\\abc.pptx"));
Assert.IsFalse(rxa.IsValid("c:abc.pptx"));
Assert.IsFalse(rxa.IsValid("c<abc.pptx"));
Assert.IsTrue(rxa.IsValid("abc.pptx"));
rxa = new ValidFileNameAttribute { AllowedExtensions = ".pptx" };
Assert.IsFalse(rxa.IsValid("abc.docx"));
Assert.IsTrue(rxa.IsValid("abc.pptx"));
}
If you're only trying to check if a string holding your file name/path has any invalid characters, the fastest method I've found is to use Split() to break up the file name into an array of parts wherever there's an invalid character. If the result is only an array of 1, there are no invalid characters. :-)
var nameToTest = "Best file name \"ever\".txt";
bool isInvalidName = nameToTest.Split(System.IO.Path.GetInvalidFileNameChars()).Length > 1;
var pathToTest = "C:\\My Folder <secrets>\\";
bool isInvalidPath = pathToTest.Split(System.IO.Path.GetInvalidPathChars()).Length > 1;
I tried running this and other methods mentioned above on a file/path name 1,000,000 times in LinqPad.
Using Split() is only ~850ms.
Using Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]") is around 6 seconds.
The more complicated regular expressions fair MUCH worse, as do some of the other options, like using the various methods on the Path class to get file name and let their internal validation do the job (most likely due to the overhead of exception handling).
Granted it's not very often you need to validation 1 million file names, so a single iteration is fine for most of these methods anyway. But it's still pretty efficient and effective if you're only looking for invalid characters.
I got this idea from someone. - don't know who. Let the OS do the heavy lifting.
public bool IsPathFileNameGood(string fname)
{
bool rc = Constants.Fail;
try
{
this._stream = new StreamWriter(fname, true);
rc = Constants.Pass;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Problem opening file");
rc = Constants.Fail;
}
return rc;
}
Windows filenames are pretty unrestrictive, so really it might not even be that much of an issue. The characters that are disallowed by Windows are:
\ / : * ? " < > |
You could easily write an expression to check if those characters are present. A better solution though would be to try and name the files as the user wants, and alert them when a filename doesn't stick.
I suggest just use the Path.GetFullPath()
string tagetFileFullNameToBeChecked;
try
{
Path.GetFullPath(tagetFileFullNameToBeChecked)
}
catch(AugumentException ex)
{
// invalid chars found
}
My attempt:
using System.IO;
static class PathUtils
{
public static string IsValidFullPath([NotNull] string fullPath)
{
if (string.IsNullOrWhiteSpace(fullPath))
return "Path is null, empty or white space.";
bool pathContainsInvalidChars = fullPath.IndexOfAny(Path.GetInvalidPathChars()) != -1;
if (pathContainsInvalidChars)
return "Path contains invalid characters.";
string fileName = Path.GetFileName(fullPath);
if (fileName == "")
return "Path must contain a file name.";
bool fileNameContainsInvalidChars = fileName.IndexOfAny(Path.GetInvalidFileNameChars()) != -1;
if (fileNameContainsInvalidChars)
return "File name contains invalid characters.";
if (!Path.IsPathRooted(fullPath))
return "The path must be absolute.";
return "";
}
}
This is not perfect because Path.GetInvalidPathChars does not return the complete set of characters that are invalid in file and directory names and of course there's plenty more subtleties.
So I use this method as a complement:
public static bool TestIfFileCanBeCreated([NotNull] string fullPath)
{
if (string.IsNullOrWhiteSpace(fullPath))
throw new ArgumentException("Value cannot be null or whitespace.", "fullPath");
string directoryName = Path.GetDirectoryName(fullPath);
if (directoryName != null) Directory.CreateDirectory(directoryName);
try
{
using (new FileStream(fullPath, FileMode.CreateNew)) { }
File.Delete(fullPath);
return true;
}
catch (IOException)
{
return false;
}
}
It tries to create the file and return false if there is an exception. Of course, I need to create the file but I think it's the safest way to do that. Please also note that I am not deleting directories that have been created.
You can also use the first method to do basic validation, and then handle carefully the exceptions when the path is used.
This check
static bool IsValidFileName(string name)
{
return
!string.IsNullOrWhiteSpace(name) &&
name.IndexOfAny(Path.GetInvalidFileNameChars()) < 0 &&
!Path.GetFullPath(name).StartsWith(#"\\.\");
}
filters out names with invalid chars (<>:"/\|?* and ASCII 0-31), as well as reserved DOS devices (CON, NUL, COMx). It allows leading spaces and all-dot-names, consistent with Path.GetFullPath. (Creating file with leading spaces succeeds on my system).
Used .NET Framework 4.7.1, tested on Windows 7.
One liner for verifying illigal chars in the string:
public static bool IsValidFilename(string testName) => !Regex.IsMatch(testName, "[" + Regex.Escape(new string(System.IO.Path.InvalidPathChars)) + "]");
In my opinion, the only proper answer to this question is to try to use the path and let the OS and filesystem validate it. Otherwise you are just reimplementing (and probably poorly) all the validation rules that the OS and filesystem already use and if those rules are changed in the future you will have to change your code to match them.

Categories

Resources