【问题标题】:String contains only a given set of characters字符串仅包含给定的字符集
【发布时间】:2011-03-18 14:56:52
【问题描述】:

我需要知道给定字符串是否是有效的 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'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”,或者我也可以在其中添加一些分隔符,这取决于我允许或不允许什么。

【问题讨论】:

  • 您是在寻找字符串字符(yYmM.. 等)还是那里的数值? (100720(今天)?

标签: c# regex


【解决方案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));

【讨论】:

  • LINQ 在 .NET 2.0 中不存在
  • @MikeD:这就是我的实现不使用它的原因;)它是一个纯粹的 .NET 2 实现。我刚刚提到 LINQ 让这一切变得简单......
  • @MikeD:它使用 String.Contains,它确实存在于 .NET 2 中(因此字符上的“ToString”:msdn.microsoft.com/en-us/library/dy85x1sa.aspx
  • @Reed:我也想到了Linq的解决方案,可惜2.0的要求不够灵活。
  • @Tergiver:这是 .NET 2 解决方案 - 不是 LINQ 解决方案。这将在 .NET 2 中完美运行。(我将编辑措辞,因为每个人都感到困惑......)
【解决方案2】:

像这样:

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

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

正则表达式的工作方式如下:

  • ^ 匹配字符串的开头
  • [...] 匹配括号中出现的任何字符
  • + 匹配与上一项匹配的一个或多个字符
  • $ 匹配字符串的结尾

没有^$ 锚点,正则表达式将匹配任何包含至少一个有效字符的字符串,因为正则表达式可以匹配字符串的任何子字符串,使用传递它。 ^$ 锚点强制它匹配整个字符串。

【讨论】:

  • 唯一正确的答案。没有人通过学习正则表达式来节省时间。
  • 同意@jwg 希望更多人了解正则表达式的力量。
  • 符号说明+1。
【解决方案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”(因为其中包括“-”字符)。

确定您希望允许的确切字符是您的判断要求。

【讨论】:

  • @Reed:我刚刚意识到,当您发布该评论时,已更新为使用 Dictionary&lt;char, byte&gt;
  • 我也想到了蛮力方法。我希望也许我错过了 System.String 或简单的 RegEx 中的某些内容。哦,好吧,只要它工作正常?
  • @Tergiver:看起来 SLaks 提供了 RegEx 选项。但通常蛮力在性能和可维护性方面胜出。至少在这种情况下,逻辑不是特别复杂,蛮力方法不需要那么多代码,我个人更喜欢它。不过,这取决于你。
  • @DanTao 我非常怀疑这是否优于正确的正则表达式方法,我不清楚为什么它更易于维护。
【解决方案4】:

类似

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

如果您搜索的是这些字符,而不是给定日期和时间的数字表示

【讨论】:

    【解决方案5】:

    由于 string 表示 IEnumerable&lt&char 的实现,所以稍微缩短了 Dan Tao 的版本>

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

    【讨论】:

    • OP 的要求之一是不使用任何 LINQ 扩展方法(如 ExceptAny)。
    【解决方案6】:

    谢谢大家。我“升级”了你们所有人,并确定了一个不使用 Dictionary/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
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-04
        • 2020-10-25
        • 1970-01-01
        相关资源
        最近更新 更多