需要引用部分文件名数组倒数第二个元素。

3

我需要在文件名数组中找到部分文件名的不同值。我希望以一行代码的方式来完成。 因此,我有一个文件名数组如下:

string[] filenames = {"aaa_ab12345.txt", "bbb_ab12345.txt", "aaa_ac12345.txt", "bbb_ac12345"}

我需要找到其ab12345部分的不同值。目前我的代码类似于:

string[] filenames_partial_distinct = Array.ConvertAll(
        filenames,
        file => System.IO.Path.GetFileNameWithoutExtension(file)
            .Split({"_","."}, StringSplitOptions.RemoveEmptyEntries)[1]
)
.Distinct()
.ToArray();

现在,我得到的文件名是 aaa_bbb_ab12345.txt 这种格式的。因此,我需要引用文件名的倒数第二部分,而不是第二部分。 那么,如果它是 Split 方法的结果,并且基于数组长度引用任意元素,该怎么办呢?类似于这样:

Array.ConvertAll(filenames, file=>file.Split(separator)[this.Length-2]).Distinct().ToArray();

换句话说,如果一个字符串方法返回一个字符串数组,我该如何根据数组长度立即选择元素:
String.Split()[third from end, fifth from end, etc.];

2
第二个代码块是无效的... 请更新以便我们可以为您提供进一步的帮助。 - Trevor
你能否给出更简洁的示例,说明你期望的输入集和期望的结果。 - ShaneDemskie
1
C# 8中的新范围/索引在这里[^2]非常适用 https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/ranges - juharr
在这个字符串中:{"aaa_ab12345.txt", "bbb_ab12345.txt", "aaa_ac12345.txt", "bbb_ac12345", "aaa_bbb_ab12345.txt", "aaa_ccc_ab12345.txt", "aaa_bbb_ac12345.txt", "aaa_ccc_ac12345.txt"},我需要找到由两个字母和四个数字组成的部分的不同值。它总是在".txt"之前的最后一个。 - miguello
2
我想要把它写在一行里。如果你重视以后需要维护你的代码的程序员的精神健康,请抑制这种欲望。 - Heretic Monkey
var q = filenames.Select(f => Path.GetFileNameWithoutExtension(f).Split('_').Last()).Distinct().ToArray(); - user10216583
3个回答

3
如果您使用GetFileNameWithoutExtension,则不会有扩展名,因此通过'_'拆分即可完成。然后您可以使用.Last()获取最后一部分。
string[] filenames_partial_distinct = Array.ConvertAll(
        filenames,
        file => Path.GetFileNameWithoutExtension(file).Split('_').Last()
    )
    .Distinct()
    .ToArray();

有了输入

string[] filenames = { "aaa_ab12345.txt", "bbb_ab12345.txt",
    "aaa_ac12345.txt", "bbb_ac12345", "aaa_bbb_ab12345.txt" };

你会得到结果。
{ "ab12345", "ac12345" }
StringSplitOptions.RemoveEmptyEntries 只有在文件名以 _ 结尾(在扩展名之前)时才需要使用。

1
简单、清晰、没有反斜杠。就像一位教授曾经说过的那样,“正则表达式很棒,但是如果可以避免使用,就应该避免。” - Wonko the Sane
这将无法针对 bbb_ac12345 进行操作。从问题中看来,它们显然都没有 '.txt' 扩展名。 - Chibueze Opata
@ChibuezeOpata,不会失败,因为GetFileNameWithoutExtension会删除扩展名和点。因此,Split始终获取没有扩展名的相同输入。此代码已经测试过并且可行(请参见最后两个代码段)。 - Olivier Jacot-Descombes

1
似乎您正在寻找这样的东西:

string[] arr = filenames.Select(n => n.Substring(n.IndexOf("_") + 1, 7)).Distinct().ToArray();

0

我通常把这样的问题转交给正则表达式处理。它们非常强大。这种方法还可以让您有机会检测意外情况并适当地处理它们。

以下是一个简陋的示例,假设我理解了您的要求:

using System;
using System.Linq;
using System.Text.RegularExpressions;

public class Program
{
    public static void Main()       
    {
        string MyMatcher(string filename)
        {
           // this pattern may need work depending on what you need - it says
           // extract that pattern between the "()" which is 2 characters and
           // 4 digits, exactly; and can be found in `Groups[1]`.
           Regex r = new Regex(@".*_(\w{2}\d{4}).*", RegexOptions.IgnoreCase);
           Match m = r.Match(filename);
           return m.Success
               ? m.Groups[1].ToString()
               : null; // what should happen here? 
        }

        string[] filenames = 
        {
            "aaa_ab12345.txt",
            "bbb_ab12345.txt",
            "aaa_ac12345.txt",
            "bbb_ac12345",
            "aaa_bbb_ab12345.txt",
            "ae12345.txt" // MyMatcher() return null for this - what should you do if this happens?
        };

        var results = filenames
            .Select(MyMatcher)
            .Distinct();

        foreach (var result in results)
        {
            Console.WriteLine(result);
        }
    }
}

给出:

ab1234
ac1234

这可以进一步优化,例如预编译的正则表达式模式、封装在类中等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接