C#:读取文本文件并进行处理

时间:2017-10-26 08:46:22

标签: c# visual-studio

我需要一个用C#编写的程序

  1. 有多少Eric Clapton的歌曲在收音机中播放。
  2. 是否有所有3个收音机播放的eric clapton歌曲。
  3. 他们在SUM播放了eric clapton歌曲的时间。
  4. 第一列包含无线电标识(1-2-3) 第二栏是关于歌曲播放时间的分钟 第三列是以秒为单位的歌曲播放时间 最后两个是表演者:歌曲

    所以文件看起来像这样:

    1 5 3深紫色:态度不好

    2 3 36 Eric Clapton:Terraplane Blues

    3 2 46 Eric Clapton:Crazy Country Hop

    3 3 25欧米茄:Ablakok

    2 4 23 Eric Clapton:如果你能抓住我

    1 3 27 Eric Clapton:Willie和The Hand Jive

    3 4 33欧米茄:一个szamuzott

    ................. 更多670行。

    到目前为止我得到了这个:

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using System.IO;
    
        namespace radiplaytime
        {
            public struct Adat
            {
                public int rad;
                public int min;
                public int sec;
                public Adat(string a, string b, string c)
                {
                    rad = Convert.ToInt32(a);
                    min = Convert.ToInt32(b);
                    sec = Convert.ToInt32(c);
                }
            }
        class Program
        {
            static void Main(string[] args)
            {
    
                String[] lines = File.ReadAllLines(@"...\zenek.txt");
                List<Adat> adatlista = (from adat in lines
                                            //var adatlista = from adat in lines
                                        select new Adat(adat.Split(' ')[0],
                                                        adat.Split(' ')[1],
                                                        adat.Split(' ')[2])).ToList<Adat>();
    
                var timesum = (from adat in adatlista
                                  group adat by adat.rad into ertekek
                                  select new
                                  {
                                      rad = ertekek.Key,
                                      hour = (ertekek.Sum(adat => adat.min) +
                                      ertekek.Sum(adat => adat.sec) / 60) / 60,
    
                                      min = (ertekek.Sum(adat => adat.min) +
                                      ertekek.Sum(adat => adat.sec) / 60) % 60,
    
                                      sec = ertekek.Sum(adat => adat.sec) % 60,
    
                                  }).ToArray();
                for (int i = 0; i < timesum.Length; i++)
                { 
                    Console.WriteLine("{0}. radio: {1}:{2}:{3} playtime",
                        timesum[i].rad,
                        timesum[i].hour,
                        timesum[i].min,
                        timesum[i].sec);
                }
                Console.ReadKey();
            }
        }
    }
    

2 个答案:

答案 0 :(得分:1)

您可以定义自定义类来存储每行的值。您将需要使用正则表达式来拆分每一行并填充您的自定义类。然后,您可以使用linq获取所需的信息。

public class Plays
    {
        public int RadioID { get; set; }
        public int PlayTimeMinutes { get; set; }
        public int PlayTimeSeconds { get; set; }
        public string Performer { get; set; }
        public string Song { get; set; }
    }

然后,您阅读文件并填充自定义播放:

String[] lines = File.ReadAllLines(@"songs.txt");
List<Plays> plays = new List<Plays>();
foreach (string line in lines)
{
    var matches = Regex.Match(line, @"^(\d+)\s(\d+)\s(\d+)\s(.+)\:(.+)$"); //this will split your line into groups
    if (matches.Success)
    {
        Plays play = new Plays();
        play.RadioID = int.Parse(matches.Groups[1].Value);
        play.PlayTimeMinutes = int.Parse(matches.Groups[2].Value);
        play.PlayTimeSeconds = int.Parse(matches.Groups[3].Value);
        play.Performer = matches.Groups[4].Value;
        play.Song = matches.Groups[5].Value;
        plays.Add(play);
    }
}

现在你已经有了歌曲列表,你可以使用linq来获得你需要的东西:

 //Get Total Eric Clapton songs played - assuming distinct songs
 var ericClaptonSongsPlayed = plays.Where(x => x.Performer == "Eric Clapton").GroupBy(y => y.Song).Count();

//get eric clapton songs played on all radio stations
var radioStations = plays.Select(x => x.RadioID).Distinct();
var commonEricClaptonSong = plays.Where(x => x.Performer == "Eric Clapton").GroupBy(y => y.Song).Where(z => z.Count() == radioStations.Count());

答案 1 :(得分:0)

字符串拆分仅在文本真正简单并且不必处理固定长度字段时才有效。它还会生成许多临时字符串,这会导致程序占用RAM中原始数量的许多倍,并且由于常量分配和垃圾回收而损害性能。

Riv的回答显示了如何使用正则表达式来解析此文件。它可以通过以下几种方式进行改进:

var pattern=@"^(\d+)\s(\d+)\s(\d+)\s(.+)\:(.+)$";
var regex=new Regex(pattern);
var plays = from line in File.ReadLines(filePath)
            let matches=regex.Match(line)
            select new Plays {
                          RadioID = int.Parse(matches.Groups[1].Value),
                          PlayTimeMinutes = int.Parse(matches.Groups[2].Value),
                          PlayTimeSeconds = int.Parse(matches.Groups[3].Value),
                          Performer = matches.Groups[4].Value,
                          Song = matches.Groups[5].Value 
                       };
  1. ReadLines返回IEnumerable<string>,而不是在缓冲区中返回所有行。这意味着解析可以立即开始
  2. 通过使用单个正则表达式,我们不必为每一行重建正则表达式。
  3. 不需要列表。该查询返回一个IEnumerable,可以直接应用其他LINQ操作。
  4. 例如:

    var durations = plays.GroupBy(p=>p.RadioID)
                         .Select(grp=>new { RadioID=grp.Key,
                                            Hours = grp.Sum(p=>p.PlayTimeMinutes + p.PlayTimeSecons/60)/60,)
                                            Mins = grp.Sum(p=>p.PlayTimeMinutes + p.PlayTimeSecons/60)%60,)
                                            Secss = grp.Sum(p=> p.PlayTimeSecons)%60)
                                  });
    

    进一步改善可能是给小组起名字:

    var pattern=@"^(?<station>\d+)\s(?<min>\d+)\s(?<sec>\d+)\s(?<performer>.+)\:(?<song>.+)$";
    
    ...
                select new Plays {
                              RadioID = int.Parse(matches.Groups["station"].Value),
                              PlayTimeMinutes = int.Parse(matches.Groups["min"].Value),
    ...
                           };
    

    你也可以摆脱Plays类并使用一个稍微复杂的LINQ查询:

    var durations = from line in File.ReadLines(filePath)
                let matches=regex.Match(line)
                let play= new {
                              RadioID = int.Parse(matches.Groups["station"].Value),
                              Minutes = int.Parse(matches.Groups["min"].Value),
                              Seconds = int.Parse(matches.Groups["sec"].Value)
                           }
                group play by play.RadioID into grp
                select new { RadioID = grp.Key,
                             Hours   = grp.Sum(p=>p.Minutes + p.Seconds/60)/60,)
                             Mins    = grp.Sum(p=>p.Minutes + p.Seconds/60)%60,)
                             Secs    = grp.Sum(p=> p.Seconds)%60)
                };
    

    在这种情况下,不会为PerformerSong生成任何字符串。这是正则表达式的另一个好处。匹配和组只是原始字符串的索引。在读取.Value之前不会生成任何字符串。这会使本案中使用的RAM减少约75%。

    获得结果后,您可以迭代它们:

    foreach (var duration in durations)
    { 
        Console.WriteLine("{0}. radio: {1}:{2}:{3} playtime",
            duration.RadioID,
            duration.Hours,
            duration.Mins,
            duration.Secs);
    }