Строка содержит только заданный набор символов
Мне нужно знать, является ли данная строка допустимой строкой формата DateTime, потому что строка может представлять другие вещи. Я пробовал DateTime.ParseExact(somedate.ToString(format), format), думая, что он будет заблокирован в недопустимом формате, но это не так.
Итак, я хорошо разбираюсь, если строка содержит только символы "yYmMdDsShH". Что-то вроде std::string.find_first_not_of будет работать, но System.String этого не имеет.
Я думал, что RegEx может сделать трюк, но я очень слаб с регулярными выражениями.
Обратите внимание, что Linq недоступен для этого (только для .NET 2.0).
Обновление
Чтобы уточнить, мне нужно знать, соответствует ли данная строка формату даты, а не что-то вроде этого:
if (input == "some special value")
... // it a special case value
else if (Environment.GetEnvironmentVariable(input))
... // it an environment variable name
else if (IsDateTimeFormatString(input))
... // it a date time format string
else if (input.IndexOfAny(Path.GetInvalidPathChars()) < 0)
... // it a file path
else
throw new Exception(); // Not a valid input
Я могу ограничить строку формата DateTime только "yYmMdDsShH", или я могу добавить в нее несколько разделительных символов, это зависит от меня, что разрешить или не разрешить.
Ответы
Ответ 1
С .NET2 вам нужно свернуть свою собственную проверку. Например, следующий метод использует foreach для проверки:
bool FormatValid(string format)
{
string allowableLetters = "yYmMdDsShH";
foreach(char c in format)
{
// This is using String.Contains for .NET 2 compat.,
// hence the requirement for ToString()
if (!allowableLetters.Contains(c.ToString()))
return false;
}
return true;
}
Если у вас была возможность использовать .NET 3.5 и LINQ, вы можете использовать Enumerable.Contains для работы с символами напрямую, а Enumerable.All. Это упростило бы следующее:
bool valid = format.All(c => "yYmMdDsShH".Contains(c));
Ответ 2
Вот так:
static readonly Regex Validator = new Regex(@"^[yYmMdDsShH]+$");
public static bool IsValid(string str) {
return Validator.IsMatch(str);
}
Регулярное выражение работает следующим образом:
-
^
соответствует началу строки
-
[...]
соответствует любому из символов, отображаемых в скобках
-
+
соответствует одному или нескольким символам, которые соответствуют предыдущему элементу
-
$
соответствует концу строки
Без привязок ^
и $
регулярное выражение будет соответствовать любой строке, содержащей хотя бы один допустимый символ, потому что регулярное выражение может соответствовать любой подстроке строки, использующей ее. Якоря ^
и $
заставляют его соответствовать всей строке.
Ответ 3
Я бы просто сделал это:
public static class DateTimeFormatHelper
{
// using a Dictionary<char, byte> instead of a HashSet<char>
// since you said you're using .NET 2.0
private static Dictionary<char, byte> _legalChars;
static DateTimeFormatHelper()
{
_legalChars = new Dictionary<char, byte>();
foreach (char legalChar in "yYmMdDsShH")
{
_legalChars.Add(legalChar, 0);
}
}
public static bool IsPossibleDateTimeFormat(string format)
{
if (string.IsNullOrEmpty(format))
return false; // or whatever makes sense to you
foreach (char c in format)
{
if (!_legalChars.ContainsKey(c))
return false;
}
return true;
}
}
Конечно, это может быть чрезмерно строгое определение, поскольку оно исключает то, что большинство людей рассмотрит допустимые форматы, такие как "yyyy-MM-dd" (так как это включает символы "-" ).
Определение того, какие символы вы хотите разрешить, является вашим решением.
Ответ 4
Что-то вроде
Regex regex = new Regex("^(y|Y|m|M|d|D|s|S|h|H)+$");
if (regex.IsMatch('DateTime String'))
{
// 'valid'
}
если вы буквально ищете эти символы, а не числовое представление для заданной даты и времени
Ответ 5
Немного короткая версия Dan Tao, поскольку строка представляет собой реализацию IEnumerable < lt; char >
[TestClass]
public class UnitTest1 {
private HashSet<char> _legalChars = new HashSet<char>("yYmMdDsShH".ToCharArray());
public bool IsPossibleDateTimeFormat(string format) {
if (string.IsNullOrEmpty(format))
return false; // or whatever makes sense to you
return !format.Except(_legalChars).Any();
}
[TestMethod]
public void TestMethod1() {
bool result = IsPossibleDateTimeFormat("yydD");
result = IsPossibleDateTimeFormat("abc");
}
}
Ответ 6
Спасибо всем. Я "поднял" всех вас и решил использовать грубую силу, которая не использует словарь /HashSet и не преобразует символы в строки:
private const string DateTimeFormatCharacters = "yYmMdDhHsS";
private static bool IsDateTimeFormatString(string input)
{
foreach (char c in input)
if (DateTimeFormatCharacters.IndexOf(c) < 0)
return false;
return true;
}
Ответ 7
Там появился новый проект NLib, который может сделать это намного быстрее:
if (input.IndexOfNotAny(new char[] { 'y', 'm', 'd', 's', 'h' }, StringComparison.OrdinalIgnoreCase) < 0)
{
// Valid
}