2010-07-20 4 views
16

Мне нужно знать, является ли данная строка допустимой строкой формата DateTime, потому что строка может представлять другие вещи. Я пробовал DateTime.ParseExact (somedate.ToString (формат), формат), думая, что это будет barf в недопустимом формате, но это не так.Строка содержит только заданный набор символов

Так что я хорошо разбираюсь, если строка содержит только символы «yYmMdDsShH». Что-то вроде std :: string.find_first_not_of будет работать, но System.String этого не имеет.

Я думал, что RegEx может сделать трюк, но я очень слаб с регулярными выражениями.

Обратите внимание, что Linq недоступен для этого (только для .NET 2.0).

Обновлено

Чтобы уточнить, мне нужно знать, если данная строка представляет собой формат даты и времени и не что-то еще вроде этого:

if (input == "some special value") 
... // it's a special case value 
else if (Environment.GetEnvironmentVariable(input)) 
... // it's an environment variable name 
else if (IsDateTimeFormatString(input)) 
... // it's a date time format string 
else if (input.IndexOfAny(Path.GetInvalidPathChars()) < 0) 
... // it's a file path 
else 
    throw new Exception(); // Not a valid input 

Я могу ограничить строку формата DateTime только «yYmMdDsShH», или я могу добавить в него несколько разделительных символов, это зависит от меня, что разрешить или не разрешить.

+1

Вы ищете строковые символы (yYmM .. и т. д.) или числовые значения, которые идут туда? (100720 (на сегодня)? – AllenG

+0

Обновлено для уточнения. – Tergiver

ответ

31

С помощью .NET2 вам необходимо свернуть свою собственную проверку. Например, следующий метод использует Еогеасп для проверки:

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

LINQ не существует в .NET 2.0 – MikeD

+2

@MikeD: Вот почему моя реализация не использует его;) Это чистая реализация .NET 2. Я только что упомянул, что LINQ делает это легко ... –

+0

@MikeD: Он использует String.Contains, который существует в .NET 2 (отсюда «ToString» для символа: http://msdn.microsoft.com/en- us/library/dy85x1sa.aspx –

4

Я просто сделать это:

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» (так как это включает символы «-»).

Определение того, какие символы вы хотите разрешить, это ваш оценочный призыв.

+2

ОП указана только .NET 2.0 - HashSet был добавлен в .NET 3.5 ... –

+0

@Reed: Я просто понял, что, поскольку вы отправляли этот комментарий - обновлялось, чтобы использовать 'Dictionary ' вместо этого. –

+0

Мне пригодился метод грубой силы. Я надеялся, что, возможно, я пропустил что-то в System.String или просто RegEx. Ну ладно, пока это работает правильно? – Tergiver

2

Что-то вроде

Regex regex = new Regex("^(y|Y|m|M|d|D|s|S|h|H)+$"); 
if (regex.IsMatch('DateTime String')) 
{ 
    // 'valid' 
} 

если вы буквально в поисках этих символов, а не числовое представление для заданной даты и времени

15

Как это:

static readonly Regex Validator = new Regex(@"^[yYmMdDsShH]+$"); 

public static bool IsValid(string str) { 
    return Validator.IsMatch(str); 
} 

регулярное выражение работ например:

  • ^ соответствует началу строки
  • [...] соответствует любому из символов, которые появляются в скобках
  • + соответствует одному или более символов, которые соответствуют предыдущему пункту
  • $ соответствует концу строки

Без якорей ^ и $ регулярное выражение будет соответствовать любой строке, содержащей хотя бы один допустимый символ, поскольку регулярное выражение может соответствовать любой подстроке строки, использующей ее. Анкеры ^ и $ заставляют его соответствовать всей строке.

+1

Единственный правильный ответ. Никто никогда не спасал время с помощью нерегулярных упражнений. – jwg

+1

Согласитесь с @jwg Пожелайте, чтобы больше людей поняли силу регулярных выражений. –

+0

Для обозначения символов +1. –

1

Немного замкнута версии Дэна Тао, поскольку строка представляет собой реализацию IEnumerable & лт & полукокса >

[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"); 
     } 
    } 
+0

Одним из требований OP было не использование каких-либо методов расширения LINQ (например, 'Except' и' Any'). –

+0

Извините. Я должен обязательно внимательно прочитать ... –

0

Спасибо всем. Я «повысил» все вы и остановились на грубой реализации силы, которая не использует словарь/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; 
} 
0

Там новый проект, NLib, который может это сделать гораздо быстрее:

if (input.IndexOfNotAny(new char[] { 'y', 'm', 'd', 's', 'h' }, StringComparison.OrdinalIgnoreCase) < 0) 
{ 
    // Valid 
} 
Смежные вопросы