これは正規表現を使用するのに適した場所のようです。具体的には、グループをキャプチャします。
以下は実際の例です。
using System;
using System.Text.RegularExpressions;
namespace RegexCaptureGroups
{
class Program
{
// Below is a breakdown of this regular expression:
// First, one or more digits followed by "d" or "D" to represent days.
// Second, one or more digits followed by "h" or "H" to represent hours.
// Third, one or more digits followed by "m" or "M" to represent minutes.
// Each component can be separated by any number of spaces, or none.
private static readonly Regex DurationRegex = new Regex(@"((?<Days>\d+)d)?\s*((?<Hours>\d+)h)?\s*((?<Minutes>\d+)m)?", RegexOptions.IgnoreCase);
public static TimeSpan ParseDuration(string input)
{
var match = DurationRegex.Match(input);
var days = match.Groups["Days"].Value;
var hours = match.Groups["Hours"].Value;
var minutes = match.Groups["Minutes"].Value;
int daysAsInt32, hoursAsInt32, minutesAsInt32;
if (!int.TryParse(days, out daysAsInt32))
daysAsInt32 = 0;
if (!int.TryParse(hours, out hoursAsInt32))
hoursAsInt32 = 0;
if (!int.TryParse(minutes, out minutesAsInt32))
minutesAsInt32 = 0;
return new TimeSpan(daysAsInt32, hoursAsInt32, minutesAsInt32, 0);
}
static void Main(string[] args)
{
Console.WriteLine(ParseDuration("30d"));
Console.WriteLine(ParseDuration("12h"));
Console.WriteLine(ParseDuration("20m"));
Console.WriteLine(ParseDuration("1d 12h"));
Console.WriteLine(ParseDuration("5d 30m"));
Console.WriteLine(ParseDuration("1d 12h 20m"));
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
編集:以下は、上記の代替の少し凝縮されたバージョンですが、どちらがより好きかはわかりません。私は通常、過度に密度の高いコードのファンではありません。正規表現を調整して、各数値に10桁の制限を設定しました。これにより、入力が少なくとも1桁から最大10桁で構成されていることがわかっているため、この関数を安全に使用できますint.Parse
(まったくキャプチャされなかった場合は、空の文字列になります。したがって、 ParseInt32ZeroIfNullOrEmptyメソッド)。
// Below is a breakdown of this regular expression:
// First, one to ten digits followed by "d" or "D" to represent days.
// Second, one to ten digits followed by "h" or "H" to represent hours.
// Third, one to ten digits followed by "m" or "M" to represent minutes.
// Each component can be separated by any number of spaces, or none.
private static readonly Regex DurationRegex = new Regex(@"((?<Days>\d{1,10})d)?\s*((?<Hours>\d{1,10})h)?\s*((?<Minutes>\d{1,10})m)?", RegexOptions.IgnoreCase);
private static int ParseInt32ZeroIfNullOrEmpty(string input)
{
return string.IsNullOrEmpty(input) ? 0 : int.Parse(input);
}
public static TimeSpan ParseDuration(string input)
{
var match = DurationRegex.Match(input);
return new TimeSpan(
ParseInt32ZeroIfNullOrEmpty(match.Groups["Days"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Hours"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Minutes"].Value),
0);
}
編集:これをもう1つ実行するために、日、時間、分、秒、ミリ秒を処理する別のバージョンを以下に追加しました。それぞれにさまざまな略語が付いています。読みやすくするために、正規表現を複数の行に分割しました。また、各コンポーネントの最後で使用して式を調整する必要がありました(\b|(?=[^a-z]))
。これは、「ms」単位が「m」単位としてキャプチャされていたためです。「[^az]」とともに使用される「?=」の特別な構文は、文字に一致することを示しますが、文字を「消費」することはありません。
// Below is a breakdown of this regular expression:
// First, one to ten digits followed by "d", "dy", "dys", "day", or "days".
// Second, one to ten digits followed by "h", "hr", "hrs", "hour", or "hours".
// Third, one to ten digits followed by "m", "min", "minute", or "minutes".
// Fourth, one to ten digits followed by "s", "sec", "second", or "seconds".
// Fifth, one to ten digits followed by "ms", "msec", "millisec", "millisecond", or "milliseconds".
// Each component may be separated by any number of spaces, or none.
// The expression is case-insensitive.
private static readonly Regex DurationRegex = new Regex(@"
((?<Days>\d{1,10})(d|dy|dys|day|days)(\b|(?=[^a-z])))?\s*
((?<Hours>\d{1,10})(h|hr|hrs|hour|hours)(\b|(?=[^a-z])))?\s*
((?<Minutes>\d{1,10})(m|min|minute|minutes)(\b|(?=[^a-z])))?\s*
((?<Seconds>\d{1,10})(s|sec|second|seconds)(\b|(?=[^a-z])))?\s*
((?<Milliseconds>\d{1,10})(ms|msec|millisec|millisecond|milliseconds)(\b|(?=[^a-z])))?",
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static int ParseInt32ZeroIfNullOrEmpty(string input)
{
return string.IsNullOrEmpty(input) ? 0 : int.Parse(input);
}
public static TimeSpan ParseDuration(string input)
{
var match = DurationRegex.Match(input);
return new TimeSpan(
ParseInt32ZeroIfNullOrEmpty(match.Groups["Days"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Hours"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Minutes"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Seconds"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Milliseconds"].Value));
}