这里有新的C#学习者。我已经浏览了许多已在此处发布的问题;如果我错过了这样一个已被问过的问题,我很抱歉。
我使用的程序生成的Excel文件的名称包含创建它们的日期。生成了数千个需要排序的Excel文件。我的任务是从这些文件名中提取信息,以便我能够在确认后将文件移动到适当的位置。我正在使用一个程序,该程序成功找到具有特定字符串的所有相关文件。我已将这些文件的名称存储在一个数组中。
示例文件名:IMPORTANT_NAME_LISTED(TEXT)[xx-xx-xx] [HH_MM] .xlsx
日期以月/日/年格式存储在“[]”内,并且100%一致(意味着每个文件将生成相同的格式,大小和日期位置)。
我一直在努力开发一个针对“。”的解决方案。在文件扩展名和提取日期之前,但我很挣扎。
我有一个初步决定,确保存储了所有文件名的数组包含值。
//code that extracts file names exists above
//file names which interest me are stored within "fileNameArray"
//Determine if the array that collected file names contains values
if (fileNameArray.Length > 1)
{
for (int k = 0; k <= fileNameArray.Length; k++)
{
//Extract date from "[xx-xx-xx] [HH-MM]"
//Transform MM/DD/YY to YY/MM/DD and temporarily store
//Compare each date value that exist within the string
//Target the most recent file - find the array index
//(Ex: 20180831 - today's date)
}
}
我的问题源于在保留数组索引的同时正确解析这些单独的数组项。
你们中的任何一个人都推荐使用方法吗? LINQ? Array.FindAll功能?
我非常感谢你的帮助。
-克里斯
编辑:有关我的情况的更多信息......
我有一个Excel文件目录,可以超过~1-3k文件。我有一个程序,它读取所有Excel文件的文件名。很多重度过滤/排序都发生在我想要实现的代码之前。
我一直在努力解决处理具有相同名称的文件的问题。例如:
我有4个文件包含相同的部分名称"DILITHIUM_CRYSTYAL_FUEL_TIME"
我的程序必须能够通过核心名称"DILITHIUM_CRYSTYAL_FUEL_TIME"
过滤/搜索文件名。如果我有多个具有相同名称的文件,我需要能够以隔离文件名中的时间戳并查找最新文件的方式解析文件名。
我的文件将始终以100%一致的方式显示文件扩展名左侧的时间戳。
我需要能够提取此时间戳,并与其他文件进行比较,并隔离最新的文件。
我也会去正则表达式,字符串解析和linq:
这里的工作示例:https://dotnetfiddle.net/veUq2N
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
public class Program
{
private static Random random = new Random();
private static Regex fileNameFragmentPattern = new Regex(@"\[(.*?)\]\.xlsx");
private const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
public static void Main()
{
var fileNames = new List<string>();
// Generate random file names
for (var i = 0; i < 10000; i++) {
fileNames.Add(RandomString(random.Next(8,10)) + "_" + RandomString(random.Next(4,5)) + "_" + "(TEXT) [" + RandomDate().ToString("MM-dd-yyyy") + "].xlsx");
}
// sort files by parsed dates
var dateSortedFileNames = fileNames.OrderByDescending( f => ExtractDate(f));
foreach (var fileName in dateSortedFileNames) {
// you can do anything with sorted files here (or anywhere else below :)
Console.WriteLine(fileName);
}
}
public static DateTime ExtractDate(string fileName) {
var fragment = fileNameFragmentPattern.Match(fileName).Value;
var month = int.Parse(fragment.Substring(1,2));
var day = int.Parse(fragment.Substring(4,2));
var year = int.Parse(fragment.Substring(7,4));
return new DateTime(year, month, day);
}
public static string RandomString(int length)
{
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
public static DateTime RandomDate(int min = -9999, int max = 9999)
{
return DateTime.Now.AddDays(random.Next(min,max));
}
}
LINQ是一个很好的选择,结合Regex
进行解析。
var dateRE = new Regex(@"\[(\d\d-\d\d-\d\d)\] \[(\d\d-\d\d)\](?=.xlsx)", RegexOptions.Compiled);
if (fileNameArray.Length > 0) {
var ans = fileNameArray.Select((n, i) => {
var dtMatch = dateRE.Match(n);
return new { Filename = n, Index = i, Filedate = DateTime.ParseExact(dtMatch.Groups[1].Value+" "+dtMatch.Groups[2].Value, "MM-dd-yy HH-mm", CultureInfo.InvariantCulture) };
})
.OrderByDescending(nid => nid.Filedate)
.First();
}
如果要以不同方式处理文件名,可以将First()
替换为其他LINQ操作。
这是一个非正则表达式解决方案。
var files = new List<string>
{
"IMPORTANT_NAME_LISTED (TEXT) [05-26-92].xlsx",
"IMPORTANT_NAME_LISTED (TEXT) [11-02-89].xlsx",
"IMPORTANT_NAME_LISTED (TEXT) [02-21-96].xlsx"
};
foreach (var fileName in files)
{
var nameOnly = Path.GetFileNameWithoutExtension(fileName);
var dateStr = nameOnly.Substring(nameOnly.Length - 9, 8);
if (DateTime.TryParseExact(dateStr, "MM-dd-yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
Console.WriteLine(date.ToShortDateString());
}
既然你提到文件名的'date'部分是100%一致的,我们知道'date'的长度总是为8.所以使用这些知识,
nameOnly.Substring(nameOnly.Length - 9, 8);
将在第一个[
之后提取字符串,并将提取在8
之前结束的]
字符。
如果您100%肯定文件扩展名将永远是.xlsx
,那么您可以进一步缩短代码。
foreach (var fileName in files)
{
var dateStr = fileName.Substring(fileName.Length - 14, 8);
if (DateTime.TryParseExact(dateStr, "MM-dd-yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
Console.WriteLine(date.ToShortDateString());
}
我想再次在这里发布,用我解决的编程问题。我过去一周忙碌,我为延迟道歉。
这是我的代码中的一个片段,可以很好地解决我的问题:
string scanToolDateFinalStgT1 = "";
DateTime scanToolDateFinalT1 = new DateTime(2000, 1, 1, 1, 1, 00);
for (int k = 0; k < scanToolT1Pass.Count(); k++)
{
string scanToolPassNameOnly = Path.GetFileNameWithoutExtension(scanToolT1Pass[k].ToString());
string scanToolDateStr = scanToolPassNameOnly.Substring(scanToolPassNameOnly.IndexOf("[") + 1, 8);
string scanToolTimeStr = scanToolPassNameOnly.Substring(scanToolPassNameOnly.LastIndexOf("[") + 1, 5);
DateTime currentScanToolDate = DateTime.ParseExact(scanToolDateStr + " " + scanToolTimeStr, "MM-dd-yy HH_mm", null);
if (currentScanToolDate > scanToolDateFinalT1)
{
scanToolDateFinalT1 = currentScanToolDate;
scanToolDateFinalStgT1 = scanToolT1Pass[k].ToString();
}
}
信息:
此代码段旨在定位'[xx-xx-xx] [xx-xx]。',这是文件名的部分唯一标识符。
该程序传入'scanToolT1Pass',这是一个文件名数组。我的任务是获取此数组并解析文件名,找到最新的文件名。
'DateTime scanToolDateFinalT1'的通用日期为1/01 / 200,1:01:00,严格用作基本比较点。我确信我的数据永远不会要求在2000年之前发生的日期。我试图让参考日期读取所有零以进行比较,但VisualStudio不赞成这一点。
说明:
是否有更先进和/或适当的方法来解析这些数据?我确定有。但是,对于初学程序员来说,这种方法对我来说很有意义,我的目标是在将来完善它。对我来说,最重要的是拥有一个首先运行的程序,而不是将大量的研究投入到抛光中。
我能够在整个程序中实现类似的for循环,以非常快的速度过滤大量数据。
再次感谢社区和@Sach&@ It Man,我的回答让我能够在我的解决方案中做出反应。
public struct DatedExcelOutput
{
public string FullName { get; }
public string Name { get; }
public DateTime CreationDate { get; }
public DatedExcelOutput(string fileName)
{
FullName = fileName;
Name = getName();
CreationDate = parseDate();
}
}
它可以像这样调用:
IEnumerable<string> fileNames = GetFiles();
var datedFiles = fileNames.Select(f => new DatedExcelOutput(f))
.OrderBy(d => d.CreationDate);
您可能最终需要在UI中对这些升序/降序进行排序吗?所以我认为抛出日期信息是没有意义的。
编辑:删除了NetMage指出的不必要的IO调用。