【问题标题】:Search for strings in a txt file with c#使用c#在txt文件中搜索字符串
【发布时间】:2021-11-14 05:37:44
【问题描述】:

我正在执行一项任务,该任务将显示 2004 年有多少国家加入了欧盟。 我还想收到 2004 年加入的国家的名称。我开始做我的工作,但我只得到塞浦路斯。 问题是有几个国家在 2004 年加入。 如何获取2004年加入的所有国家名称? 我在控制台应用程序(.NET Framework)中完成了我的任务。 对于该任务,我使用了一个包含数据的 txt 文件。 这是我的代码:

  class Program
    {
        static List<Country> joining = new List<Country>(); 
        static void read()
        {
            string[] rows=File.ReadAllLines("EU.txt");
            foreach (var item in rows)
            {
                joining.Add(new Country(item));
            }
        }
        
        static void Main(string[] args)
        {
            read();
            
            
            
            // how many countries:
            Console.WriteLine($"{joining.Count(item =>item.date.Split('.')[1] == "05" )}countries joined.");
            //names:
            Console.WriteLine($"Country names:{joining.Find(item =>item.date.Split('.')[1] == "05" ).name}"); // !!! this code is bad

    
            Console.ReadKey();
        }
    }

    class Country
    {
        //Fields
        public string date, name;

        //ctor
        public Country(string row)
        {
            name=row.Split(';')[0];
            date = row.Split(';')[1];
        }
    }

EU.txt:

奥地利;1995.01.01 比利时;1958.01.01 保加利亚;2007.01.01 塞浦路斯;2004.05.01 捷克语;2004.05.01 丹麦;1973.01.01 英国;1973.01.01 爱沙尼亚;2004.05.01 芬兰;1995.01.01 法国;1958.01.01 希腊;1981.01.01 荷兰;1958.01.01 克罗地亚;2013;07.01 爱尔兰;1973.01.01 波兰;2004.05.01 拉脱维亚;2004.05.01 立陶宛;2004.05.01 卢森堡;1958.01.01 匈牙利;2004.05.01 马耳他;2004.05.01 德国;1958.01.01 意大利;1958.01.01 葡萄牙;1986.01.01 罗马尼亚;2007.01.01 西班牙;1986.01.01 瑞典;1995.01.01 斯洛伐克;2004.05.01 斯洛文尼亚;2004.05.01

【问题讨论】:

  • joining.Find(...) 只会找到第一项(在您的情况下为Cyprus)。
  • 您想要 2004 年,还是想要 5 月?因为问题文本说明了一件事,而问题代码说明了另一件事。
  • 另外,从不将示例数据发布为图像。

标签: c# .net console-application txt


【解决方案1】:

好吧,joining.Find(...) 只会找到 first 项(在您的情况下为 Cyprus)。您可以改用 Linq Where。请注意,您应该与"2004"(年)进行比较,而不是与"05"(月)进行比较:

  using System.Linq;

  ...

  // names:
  var names = joining
    .Where(item => item.date.Split('.')[0] == "2004")
    .Select(item => item.name);  

  // let's join all the names by ", ":
  Console.WriteLine($"Country names:{string.Join(", ", names)}"); 

编辑: 但是,像item.date.Split('.')[1] == "2004" 这样的比较看起来很难看(为什么我在查询日期时要考虑字符串?)。 让Country 类为自己提供帮助(日期、名称等):

class Country {
    public string Name {get;}
    public DateTime JoinedDate {get;}

    public Country(string row) {
      if (row == null)
        throw new ArgumentNullException(nameof(row));  

      string[] items = row.Split(';', 2);

      if (items.Length < 2)
        throw new FormatException("Invalid row format"); 

      Name = items[0];
      JoinedDate = DateTime.ParseExact(items[1], "yyyy.M.d");
    }

    public override string ToString() => Name;
}

然后是Linq(我们查询EU.txt文件):

static void Main(string[] args) {
  List<Country> joined2004 = File
    .ReadLines("EU.txt")
    .Select(line => new Country(line))
    .Where(country => country.JoinedDate.Year == 2004)
    .ToList();

  Console.WriteLine($"{joined2004.Count} countries joined.");
  Console.WriteLine($"{string.Join(", ", joined2004)}")  
}

【讨论】:

    【解决方案2】:

    这里有很多小变化:

    class Program
    {
        static List<Country> Countries; 
    
        // Use types and methods that avoid needing to load full sets into RAM all at once
        // for as long as possible. That means IEnumerable rather than List and ReadLines() 
        // rather than ReadAllLines().
        // It's also better for the read() function accept a value and return the result
        static IEnumerable<Country> ReadCountries(string filePath)
        {
            // No need to allocate so much RAM via ReadAllLines()
            // Better to just have one line in RAM at a time until everything is loaded
            return File.ReadLines(filePath)
                       .Select(line => new Country(line));
        }
        
        static void Main(string[] args)
        {
            Countries = ReadCountries("EU.txt").ToList();
            var JoinedIn2004 = Countries.Where(c => c.date.Year == 2004);            
            
            Console.WriteLine($"{JoinedIn2004.Count()} countries joined.\nCountry name:");
            // need to loop through the list to get all the names
            foreach(var country in JoinedIn2004)
            {
               Console.WriteLine(country.name); 
            }
            // Alternatively, if you really don't want to write a loop:
            // Console.WriteLine(string.Join("\n", JoinedIn2004));
    
            Console.ReadKey(true);
        }
    }
    
    class Country
    {
        // properties > fields
        public string name {get;set;}
        public DateTime date {get;set;} //Parse an actual DateTime for this!
        
        //personally I lean towards a static builder method (Country.FromTextLine())
        // for this, to decouple building the type from any specific file,
        // but I also get it's overkill here.
        public Country(string row)
        {
            var format = "yyyy.MM.dd";
            var fields = row.Split(';');
    
            name = fields[0];
            date = DateTime.ParseExact(fields[1], format, null);
        }
    }
    

    【讨论】:

      【解决方案3】:
          List<Country> result = joining.FindAll(item =>item.date.Split('.')[1] == "05");
          Console.Write($"Country names:");
          foreach(Country country in result)
          {
              Console.Write($"{country.name} ");
          }
          Console.WriteLine();
      

      【讨论】:

        猜你喜欢
        • 2021-10-20
        • 1970-01-01
        • 1970-01-01
        • 2014-02-06
        • 1970-01-01
        • 2011-01-12
        • 2011-01-31
        • 2018-11-27
        • 2013-10-10
        相关资源
        最近更新 更多