2010-07-20 12 views
16

Necesito saber si una cadena dada es una cadena de formato de fecha y hora válida porque la cadena puede representar otras cosas. Intenté DateTime.ParseExact (somedate.ToString (formato), formato) pensando que sería un error en un formato no válido, pero no es así.Cadena contiene solo un conjunto dado de caracteres

Así que estoy bien con simplemente probar si la cadena contiene solo caracteres "yYmMdDsShH". Algo como std :: string.find_first_not_of funcionaría, pero System.String no tiene esto.

Pensé que RegEx podría hacer el truco, pero estoy muy débil con expresiones regulares.

Tenga en cuenta que Linq no está disponible para esta (solo .NET 2.0).

Actualizado

Para aclarar, necesito saber si una determinada cadena representa un formato de fecha y no otra cosa como esta:

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 

puedo restringir una cadena de formato DateTime a solamente "yYmMdDsShH", o puedo agregarle algunos caracteres separadores, depende de mí permitir o no permitir.

+1

¿Está buscando caracteres de cadena (yYmM, etc.) o los valores numéricos que van allí? (?. 100720 (por hoy) – AllenG

+0

Actualizado aclarar – Tergiver

Respuesta

31

Con .NET2, necesita rodar su propio cheque para esto. Por ejemplo, el siguiente método utiliza un foreach para comprobar:

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

Si tuviera la opción de usar .NET 3.5 y LINQ, se podría utilizar Enumerable.Contains trabajar con caracteres directamente, y Enumerable.All. Esto simplificaría la anterior a:

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

LINQ no existe en .NET 2.0 – MikeD

+2

@MikeD: Es por eso que mi aplicación no lo usa;) Es una aplicación pura .NET 2. Acabo de mencionar que LINQ hace que esto sea fácil ... –

+0

@MikeD: Está usando String.Contains, que SI EXISTE en .NET 2 (de ahí el "ToString" en el carácter: http://msdn.microsoft.com/en- es/library/dy85x1sa.aspx –

4

que acababa de hacer esto:

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

Por supuesto, esto podría ser una definición excesivamente estricta, ya que descarta lo que la mayoría de la gente consideraría formatos válidos como "aaaa-MM-dd" (ya que incluye los caracteres "-").

Determinar exactamente qué caracteres desea permitir es su decisión.

+2

OP especificado .NET 2.0 solamente - HashSet se agregó en .NET 3.5 ... –

+0

@Reed: Me acabo de dar cuenta de que al publicar ese comentario, se actualizó para usar un 'Diccionario ' en su lugar. –

+0

También se me ocurrió el método de la fuerza bruta. Esperaba que quizás me perdí algo en System.String o un simple RegEx. Ah, bueno, mientras funcione, ¿verdad? – Tergiver

2

Algo así como

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

Si usted es, literalmente, la búsqueda de esos caracteres y no la representación numérica para una fecha determinada y el tiempo

15

De esta manera:

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

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

Las obras de expresiones regulares de esta manera:

  • ^ coincide con el comienzo de la cadena
  • [...] coincide con alguno de los personajes que aparecen en los soportes
  • + coincide con uno o más caracteres que coinciden con el punto anterior
  • $ coincide con el final de la cadena

Sin los anclajes ^ y $, la expresión regular coincidirá con cualquier cadena que contenga al menos un carácter válido, ya que una expresión regular puede coincidir con cualquier subcadena de la cadena. Utilícela. Los anclajes ^ y $ lo obligan a hacer coincidir toda la cadena.

+1

La única respuesta correcta. Nadie ha ahorrado tiempo al "no" aprender expresiones regulares. – jwg

+1

De acuerdo con @jwg Desearía que más personas entendieran el poder de las expresiones regulares. –

+0

Para la explicación de símbolos +1. –

1

ligeramente en cortocircuito la versión de Dan Tao ya cadena representa una implementación de IEnumerable & lt & carbón >

[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

Uno de los requisitos de OP no era utilizar ningún método de extensión LINQ (como 'Except' y' Any'). –

+0

Lo siento. Definitivamente debería leer con más cuidado ... –

0

Gracias a todos. I 'aumenté' todos ustedes y conformé con una aplicación de fuerza bruta que no utiliza un diccionario/HashSet y no se convierte caracteres de cadenas:

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

Hay un nuevo proyecto, NLib, lo que puede hacer esto mucho más rápido:

if (input.IndexOfNotAny(new char[] { 'y', 'm', 'd', 's', 'h' }, StringComparison.OrdinalIgnoreCase) < 0) 
{ 
    // Valid 
} 
Cuestiones relacionadas