2

我有一个输入文件,其中包含有关艺人及其表演得分的数据。例如,

1. Bill Monohan from North Town 10.54
2. Mary Greenberg from Ohio 3.87
3. Sean Hollen from Markell 7.22

我希望能够从一行中取出最后一个数字(他们的分数),对其进行一些数学运算,然后用新分数替换旧分数。这是我正在尝试做的简短代码:

string line;
StreamReader reader = new StreamReader(@"file.txt");

//Read each line and split by spaces into a List.
while ((line = reader.ReadLine())!= null){

//Find last item in List and convert to a Double in order to perform calculations.
   List<string> l = new List<string>();
   l = line.Split(null).ToList();
   string lastItem = line.Split(null).Last();
   Double newItem = Convert.ToDouble(lastItem);

   /*Do some math*/
   /*Replace lastItem with newItem*/
   System.Console.WriteLine(line); }

当我编写新行时,没有任何变化,但我希望 lastItem 现在在行尾与 newItem 切换。我试过使用:

l[l.Length - 1] = newItem.ToString();

但我没有运气。我只需要最好的方法来替换这样的字符串 List 的最后一个值。我已经做了几个小时了,我几乎走到了尽头。请各位c#高手帮帮我!

4

6 回答 6

2

您可以使用正则表达式MatchEvaluator从每一行获取数字,进行计算,并将原始数字替换为新数字:

string line = "1. Bill Monohan from North Town 10.54";
line = Regex.Replace(line, @"(\d+\.?\d*)$", m => {
            decimal value = Decimal.Parse(m.Groups[1].Value);
            value = value * 2; // calculation
            return value.ToString();
        });

此正则表达式在输入字符串的末尾捕获十进制数。输出:

1. Bill Monohan from North Town 21.08
于 2013-09-23T09:06:23.387 回答
0

这应该有效:

//var l = new List<string>(); // you don't need this
var l = line.Split(null).ToList();
var lastItem = l.Last(); // line.Split(null).Last(); don't split twice
var newItem = Convert.ToDouble(lastItem, CultureInfo.InvariantCulture);
/*Do some math*/
/*Replace lastItem with newItem*/
l[l.Count - 1] = newItem.ToString(); // change the last element
//Console.WriteLine(line); // line is the original string don't work
Console.WriteLine(string.Join(" ", l)); // create new string
于 2013-09-23T09:00:39.043 回答
0

在执行 WriteLine 之前,您不会对 line 对象进行任何更改。

您将不得不重建您的生产线,如下所示:

var items = string.Split();
items.Last() = "10";//Replace
var line = string.Join(" ", items)

提示:字符串是不可变的,请查阅。

于 2013-09-23T08:54:08.473 回答
0

这可能会为您完成这项工作。不过,如果可能的话,关于读取文件的一句话,即它们适合内存,一次读取整个文件,它给你一个磁盘访问权限(嗯,取决于文件大小,但是是的),你不必担心文件句柄。

  // Read the stuff from the file, gets an string[]
  var lines = File.ReadAllLines(@"file.txt");

  foreach (var line in lines)
  {
      var splitLine = line.Split(' ');
      var score = double.Parse(splitLine.Last(), CultureInfo.InvariantCulture);

      // The math wizard is in town!
      score = score + 3;

      // Put it back
      splitLine[splitLine.Count() - 1] = score.ToString();

      // newLine is the new line, what should we do with it?
      var newLine = string.Join(" ", splitLine);
      // Lets print it cause we are out of ideas!
      Console.WriteLine(newLine);
  }

你想对最终结果做什么?你想把它写回文件吗?

于 2013-09-23T09:07:38.920 回答
0

尝试这个

  string subjectString = "Sean Hollen from Markell 7.22";

  double Substring =double.Parse(subjectString.Substring(subjectString.IndexOf(Regex.Match(subjectString, @"\d+").Value), subjectString.Length - subjectString.IndexOf(Regex.Match(subjectString, @"\d+").Value)).ToString());

  double NewVal = Substring * 10;  // Or any of your operation

  subjectString = subjectString.Replace(Substring.ToString(), NewVal.ToString());

注意:如果数字在同一行出现两次,这将不起作用

于 2013-09-23T09:08:18.580 回答
0

您正在循环中创建和初始化列表,因此它始终只包含当前行。你想找到所有艺人的最高分还是每个艺人的最高分(以防一个艺人在文件中重复)?

但是,这里有一种方法可以同时为您提供:

var allWithScore = File.ReadAllLines(path)
    .Select(l =>
    {
        var split = l.Split();
        string entertainer = string.Join(" ", split.Skip(1).Take(split.Length - 2));
        double score;
        bool hasScore = double.TryParse(split.Last(), NumberStyles.Float, CultureInfo.InvariantCulture, out score);
        return new { line = l, split, entertainer, hasScore, score };
    })
    .Where(x => x.hasScore);
// highest score of all:
double highestScore = allWithScore.Max(x => x.score);
// entertainer with highest score 
var entertainerWithHighestScore = allWithScore
    .OrderByDescending(x => x.score)
    .GroupBy(x => x.entertainer)
    .First();
foreach (var x in entertainerWithHighestScore)
    Console.WriteLine("Entertainer:{0} Score:{1}", x.entertainer, x.score);
// all entertainer's highest scores:
var allEntertainersHighestScore = allWithScore
    .GroupBy(x => x.entertainer)
    .Select(g => g.OrderByDescending(x => x.score).First());
foreach (var x in allEntertainersHighestScore)
    Console.WriteLine("Entertainer:{0} Score:{1}", x.entertainer, x.score);
于 2013-09-23T09:11:14.963 回答