鉴于此代码:
// Decode the text string
string test = "Version 21.1.0 - 2021 Edition (22nd March 2021)";
string[] textitems = test.Split(' ');
// The text should split down like this:
// [0] Version
// [1] 21.1.0
// [2] -
// [3] 2021
// [4] Edition
// [5] (22nd
// [6] March
// [7] 2021)
我创建了一个 enum
来使用:
enum UpdateInfo
{
Version = 1,
Edition = 3,
Day = 5,
Month = 6,
Year = 7
}
我感兴趣的信息是:
Version
和 Edition
很简单:
writer.WriteAttributeString("Version", textitems[(int)UpdateInfo.Version]);
writer.WriteAttributeString("Edition", textitems[(int)UpdateInfo.Edition]);
但 Date
不是。我发现我无法解析(例如):
(22nd March 2021)
我想要短日期,所以我在研究后想出了以下代码:
// Rebuild date as short date
// Day - strip off "(" and "st", "nd", "rd" or "th"
string day = string.Empty;
for (int i = 0; i < textitems[(int)UpdateInfo.Day].Length; i++)
{
if (Char.IsDigit(textitems[(int)UpdateInfo.Day][i]))
day += textitems[(int)UpdateInfo.Day][i];
}
// Rebuilt long date
string datetest = day + " " + textitems[(int)UpdateInfo.Month] + " " + textitems[(int)UpdateInfo.Year];
// Remove trailing ")"
datetest = datetest.Trim(')');
// Now we can parse the long date string
DateTime date = DateTime.ParseExact(datetest, "d MMMM yyyy", CultureInfo.InstalledUICulture, DateTimeStyles.None);
if (date != null)
writer.WriteAttributeString("Date", date.ToShortDateString());
有没有更简单的方法可以在不增加代码的情况下实现相同的结果?
注意:
<p class="rvps2">
<img alt="New Version Icon"
style="vertical-align: middle; padding : 1px; margin : 0px 5px;"
src="lib/IMG_NewVersion.png">
<span class="rvts16">Version 21.1.0 - 2021 Edition</span>
<span class="rvts15"> (22nd March 2021)</span>
</p>
所以我实际上有一个 HtmlNode
(p
元素`)。
答案 0 :(得分:2)
我不会用空格分割,太多了。我会用 "-"
分割,然后使用正则表达式来提取日期部分。然后使用 TryParseExact
和 dd'nd' MMMM yyyy
很容易:
string[] textitems = test.Split('-');
string version = textitems[0].Trim();
string edition = textitems[1].Substring(0, textitems[1].IndexOf("(")).Trim();
string dateStr = Regex.Match(textitems[1], @"\(([^)]*)\)").Groups[1].Value;
string[] formats = { "d'st' MMMM yyyy", "d'nd' MMMM yyyy" };
bool validDate = DateTime.TryParseExact(dateStr, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date );
我还添加了 d'st' MMMM yyyy
,因为我可以想象这将是您的下一个问题。另一种选择是以以下格式包含括号:"'('d'nd' MMMM yyyy')'"
.
你可能想先添加一些代码来验证输入,我已经省略了。
答案 1 :(得分:2)
为此,我什至不会费心拆分文本,您可以使用正则表达式和命名匹配来做到这一点。
string test = "Version 21.1.0 - 2021 Edition (22nd August 2021)";
var regex = new Regex(@"Version (?'version'[\d.]+) - (?'edition'\d+) Edition \((?'date'[^)]+)", RegexOptions.None);
var matches = regex.Matches(test);
var version = matches[0].Groups["version"].Value;
var edition = matches[0].Groups["edition"].Value;
var dateString = matches[0].Groups["date"].Value;
// remove date ordinal before parsing
dateString = Regex.Replace(dateString, @"^(\d+)(st|nd|rd|th)", "$1");
var date = DateTime.ParseExact(dateString, "dd MMMM yyyy", CultureInfo.CurrentCulture);
date.ToShortDateString().Dump();
通常我会使用 TryParseExact
并正确处理任何解析异常。
您可以在此处获得主要正则表达式的解释:https://regex101.com/r/Nzpa5h/1
答案 2 :(得分:0)
我想出了一个结合了这两种方法的解决方案。由于原始数据实际上是一个 HtmlNode
(如问题底部所示)并且已经分成两个 span
元素,我决定这样做:
// The paragraph element should only have two "span" elements
var listSpan = itemParagraph.Descendants("span");
if(listSpan != null)
{
if(listSpan.Count() == 2)
{
// The first "span" element should contain: Version 21.1.0 - 2021 Edition
var regex = new Regex(@"Version (?'version'[\d.]+) - (?'edition'\d+) Edition", RegexOptions.None);
var matches = regex.Matches(listSpan.ElementAt(0).InnerText.Trim());
writer.WriteStartElement("Update");
writer.WriteAttributeString("Version", matches[0].Groups["version"].Value);
writer.WriteAttributeString("Edition", matches[0].Groups["edition"].Value);
// The second "span" element should contain: eg. (22nd March 2021)
string dateString = listSpan.ElementAt(1).InnerText.Trim(' ', '(', ')');
string[] formats =
{
"d'st' MMMM yyyy",
"d'nd' MMMM yyyy",
"d'rd' MMMM yyyy",
"d'th' MMMM yyyy"
};
if (DateTime.TryParseExact(dateString,
formats, CultureInfo.CurrentUICulture, DateTimeStyles.None, out DateTime dateRevision))
{
writer.WriteAttributeString("Date", dateRevision.ToShortDateString());
}
}
}
我承认我不太了解这段代码的实际工作原理:
var regex = new Regex(@"Version (?'version'[\d.]+) - (?'edition'\d+) Edition", RegexOptions.None);
var matches = regex.Matches(listSpan.ElementAt(0).InnerText.Trim());
以上代码是根据提供的答案之一修改的。但它有效。 :)
我决定使用公认的答案方法构建日期,因为我了解它在做什么,而不是正则表达式的建议。
@phuzi 也许您可以添加一些解释或指示来充实您关于正则表达式语法的答案?