2010-07-20 37 views
16

Tôi cần phải biết nếu một chuỗi đã cho là chuỗi định dạng DateTime hợp lệ vì chuỗi có thể đại diện cho những thứ khác. Tôi đã thử DateTime.ParseExact (somedate.ToString (định dạng), định dạng) nghĩ rằng nó sẽ barf trên một định dạng không hợp lệ, nhưng nó không.Chuỗi chỉ chứa một tập hợp các ký tự

Vì vậy, tôi rất tốt khi chỉ thử nghiệm nếu chuỗi chỉ chứa các ký tự "yYmMdDsShH". Một cái gì đó như std :: string.find_first_not_of sẽ làm việc, nhưng System.String không có điều này.

Tôi nghĩ rằng RegEx có thể làm thủ thuật, nhưng tôi rất yếu với biểu thức chính quy.

Lưu ý rằng LINQ không khả dụng cho phiên bản này (chỉ dành cho .NET 2.0).

Cập nhật

Để làm rõ, tôi cần phải biết nếu một chuỗi nhất định thể hiện một định dạng thời gian ngày và không phải cái gì khác như thế này:

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 

tôi có thể giới hạn một chuỗi định dạng DateTime chỉ "yYmMdDsShH", hoặc tôi có thể thêm một vài ký tự dấu phân cách vào nó là tốt, nó thuộc vào tôi những gì cho phép hoặc không cho phép.

+1

Bạn đang tìm kiếm các ký tự chuỗi (yYmM .. vv) hoặc các giá trị số có đến đó? (100720 (cho ngày hôm nay)? – AllenG

+0

Cập nhật để làm rõ. – Tergiver

Trả lời

31

Với .NET2, bạn cần cuộn séc của riêng mình để thực hiện việc này. Ví dụ, các phương pháp sau đây sử dụng một foreach để kiểm tra:

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; 
} 

Nếu bạn có tùy chọn sử dụng .NET 3.5 và LINQ, bạn có thể sử dụng Enumerable.Contains để làm việc với các nhân vật trực tiếp, và Enumerable.All. Điều này sẽ đơn giản hóa ở trên để:

bool valid = format.All(c => "yYmMdDsShH".Contains(c)); 
+0

LINQ không tồn tại trong .NET 2.0 – MikeD

+2

@MikeD: Đó là lý do tại sao việc triển khai của tôi không sử dụng nó;) Đây là một triển khai .NET 2 thuần túy. Tôi chỉ đề cập rằng LINQ làm cho điều này dễ dàng ... –

+0

@MikeD: Nó đang sử dụng String.Contains, có tồn tại trong .NET 2 (do đó "ToString" trên ký tự: http://msdn.microsoft.com/en- us/library/dy85x1sa.aspx –

4

tôi chỉ muốn làm điều này:

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; 
    } 
} 

Tất nhiên, đây có thể là một định nghĩa quá nghiêm ngặt, vì nó bác bỏ những gì hầu hết mọi người sẽ xem xét định dạng hợp lệ chẳng hạn như "yyyy-MM-dd" (vì bao gồm ký tự "-").

Xác định chính xác những ký tự bạn muốn cho phép là cuộc gọi phán đoán của bạn.

+2

OP được chỉ định .NET 2.0 chỉ - HashSet được thêm vào trong .NET 3.5 ... –

+0

@Reed: Tôi vừa nhận ra rằng khi bạn đăng nhận xét đó - được cập nhật để sử dụng 'Dictionary ' thay thế. –

+0

Phương pháp bạo lực cũng xảy ra với tôi. Tôi đã hy vọng có thể tôi bị mất một cái gì đó trong System.String hoặc một RegEx đơn giản. Oh, miễn là nó hoạt động đúng không? – Tergiver

2

Something như

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

nếu bạn đang tìm kiếm theo nghĩa đen những ký tự và không đại diện cho số một ngày nhất định và thời gian

15

Như thế này:

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

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

Các công trình regex như thế này:

  • ^ phù hợp với đầu của chuỗi
  • [...] khớp với bất kỳ của các nhân vật xuất hiện trong khung
  • + trận đấu một hoặc ký tự hơn phù hợp với mục trước
  • $ phù hợp với kết thúc của chuỗi

Nếu không có các neo ^$, regex sẽ khớp với bất kỳ chuỗi nào có chứa ít nhất một ký tự hợp lệ, vì regex có thể khớp với bất kỳ chuỗi con nào của chuỗi sử dụng. Các neo ^$ buộc nó khớp với toàn bộ chuỗi.

+1

Câu trả lời đúng và duy nhất. Không ai từng tiết kiệm thời gian bằng cách _not_ học regex. – jwg

+1

Đồng ý với @jwg Chúc thêm nhiều người hiểu sức mạnh của cụm từ thông dụng. –

+0

Để biết các ký hiệu giải thích +1. –

1

Hơi thiếu phiên bản Dan Tao kể từ chuỗi đại diện cho một thực hiện 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"); 
     } 
    } 
+0

Một trong những yêu cầu của OP là không sử dụng bất kỳ phương pháp mở rộng LINQ nào (như 'Ngoại trừ' và 'Bất kỳ'). –

+0

Xin lỗi. Tôi chắc chắn nên đọc kỹ hơn ... –

0

Cảm ơn mọi người. Tôi 'upped' tất cả các bạn và giải quyết trên một thực hiện brute force mà không sử dụng một từ điển/HashSet và không chuyển đổi ký tự thành các chuỗi:

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

Có một dự án mới, NLib, có thể làm điều này nhanh hơn nhiều:

if (input.IndexOfNotAny(new char[] { 'y', 'm', 'd', 's', 'h' }, StringComparison.OrdinalIgnoreCase) < 0) 
{ 
    // Valid 
} 
Các vấn đề liên quan