0

全て、

私は C++ でいくつかのプログラミング演習を行っており、それらを C# や他の言語に翻訳してブラッシュアップしようとしています。

この例は、Ch. Nell Dale と Chip Weems の「Programming and Problem Solving with C++」(第 5 版) の 521 ~ 522 ページの 11.2。これは、このファイル (学生の名前、GPA、4 つの成績、コースの成績) を取り込むプログラムです。次のように呼びましょうrec.in

メアリー・アボット 3.4 80 90 60 99 B

ボブ・ベイカー 4.0 90 90 90 95 A

サリー・カーター 2.0 70 70 70 65 C

ビル・ダンスク 3.0 65 50 60 70 D

JoEllen Zureck 1.9 90 95 80 99 A

そして(多かれ少なかれ)それを別のファイルにコピーするだけです。

これを行うコードは次のとおりです。

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

const int MAX_STUDENTS = 150;

enum GradeType{A,B,C,D,F};

struct StudentRec
{
    string stuName;
    float gpa;
    int examScore[4];
    GradeType courseGrade;
};
StudentRec gradeBook[MAX_STUDENTS];

int main()
{
    StudentRec record[MAX_STUDENTS];
    ofstream outFile;
    outFile.open("rec.out");
    ifstream inFile;
    inFile.open("rec.in");
    for (int count = 0; count < MAX_STUDENTS; count++)
    ReadValues(inFile, record[count]);
    for (int count = 0; count <= MAX_STUDENTS; count++)
    PrintValues(outFile, record[count]);
    inFile.close();
    outFile.close();
    return 0;
}

void ReadValues(ifstream& inFile, StudentRec& record)
{
    char letter;
    char throwAway;

    getline(inFile, record.stuName);
    inFile >> record.gpa>>record.examScore[0]
    >> record.examScore[1] >> record.examScore[2]
    >> record.examScore[3] >> letter;

    inFile.get(throwAway);

    switch(letter)
    {
        case 'A' : record.courseGrade = A;
           break;
        case 'B' : record.courseGrade = B;
           break;
        case 'C' : record.courseGrade = C;
           break;
            case 'D' : record.courseGrade = D;
           break;
        case 'F' : record.courseGrade = F;
               break;
   }
}

void PrintValues(ofstream& outFile, StudentRec& record)
{
    outFile << record.stuName << endl;
    outFile << record.gpa << ' ' << record.examScore[0] << ' '
        << record.examScore[1] << ' '
        << record.examScore[2] << ' '
        << record.examScore[3] << ' ';
    switch (record.courseGrade)
    {
        case A : outFile << 'A';
        break;
        case B : outFile << 'B';
        break;
        case C : outFile << 'C';
        break;
        case D : outFile << 'D';
        break;
        case F : outFile << 'F';
        break;
    }

outFile << endl;
}

私はC#への翻訳から始めています。以前に C# の作業を行ったことがありますが、コンソールの作業は行っていません。その結果、少し... 面倒です... 翻訳に取り組んでいます。私は、getlineC# で C++ の機能を一致させることに少し混乱しています。もちろん、ありますが、System.IO.StreamReaderそれは一度に1行ずつファイルを読み取るだけです。getline上記のように、ストリーム形式で実行します。これにより、単語/文字間のスペース/改行を使用して分割されます。C# のライブラリの選択で同じ結果を得るにはどうすればよいですか? 私はSystem.IO.StreamReader解決策と正確に結婚していません。

これが私が持っているものの始まりです:

using System;
using System.IO;

namespace _112a
{
    class Program
    {
        const int MAX_STUDENTS = 150;
        enum GradeType{A,B,C,D,F};
        struct StudentRec{
            string stuName;
            float gpa;
            GradeType courseGrade;
        };

        StudentRec[] gradeBook = new StudentRec[MAX_STUDENTS];

        static void Main(string[] args)
        {
            StudentRec[] record = new StudentRec[MAX_STUDENTS];
            System.IO.StreamWriter outFile = new System.IO.StreamWriter("rec.out"); 
            System.IO.StreamReader inFile = new System.IO.StreamReader("rec.in");

            for (int count = 0; count < MAX_STUDENTS; count++)
            {
                ReadValues(inFile, record[count]);
            }

            for (int count = 0; count <= MAX_STUDENTS; count++)
            {
                PrintValues(outFile, record[count]);
            }

            inFile.Close();
            outFile.Close();
        }

        static void ReadValues(StreamReader inFile, StudentRec record)
        {
            char letter;
            char throwAway;

            /*can't use getline, what do?*/

            inFile.ReadLine();

            switch (letter)
            {
                case 'A':
                    record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "A");
                    break;
                case 'B':
                    record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "B");
                    break;
                case 'C':
                    record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "C");
                    break;
                case 'D':
                    record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "D");
                    break;
                case 'F':
                    record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "F");
                    break;
            }


        }

        static void PrintValues(StreamWriter outFile, StudentRec record)
        {
            outFile.Write("{0}\n{1} {2} {3} ", record.stuName, record.examScore[0], record.examScore[1], record.examScore[2], record.examScore[3]);

            switch(record.courseGrade)
            {
                case GradeType.A: 
                    outFile.Write("A\n");
                    break;
                case GradeType.B: 
                    outFile.Write("B\n");
                    break;
                case GradeType.C: 
                    outFile.Write("C\n");
                    break;
                case GradeType.D:
                    outFile.Write("D\n");
                    break;
                case GradeType.F:
                    outFile.Write("F\n");
            }
        }
    }
}

メソッドに表示されるスイッチ構造に関して追加の質問がありますPrintValues。それぞれのケースで、C++ ファイルで指定されているように、record.courseGradeフィールドを取得して、後ろに指定された引数と比較するだけcaseです。型に強い言語である C# では、このようなことは起こりません... char'A' をと比較するrecord.courseGradeと、型の不一致エラーが発生します。または、一重引用符を付けずにそのままにしておく (したがって、フィールドとして残す) と、 How do I best deal with this?- RESOLVEDrecord.courseGradeのエラーが発生します。The name 'A' does not exist in the current context.

ReadLine() を使用した私の混乱は、それがどのように機能するかに起因します。この場合、構造体の複数のメンバーStudentRecが満たされていますが、それらは構造体の個別のエンティティです。私の恐れは次のようなことをするでしょう:

StudentRec.stuName = inFile.ReadLine();

StudentRec.stuName他の構造体フィールドには何も入力せずに、行全体を入力します。

さらに、letter割り当てが解除されてスイッチとして使用されるという問題があります。これは、 から値を受け取っていないためReadLineです。ReadLineただし、実際に物事を分割する場合、それは学術的な解決策です。

4

2 に答える 2

3

StreamReader と Writer をそれぞれ使用します。あなたが探している可能性が高いメソッドは と ですReadLine。StreamReaderWriteLineドキュメントの下部には、ニーズに合った実際の例があります。while ループ内のファイル パスとロジックを変更するだけです。ドキュメントはここにあります。

http://msdn.microsoft.com/en-us/library/system.io.streamreader.aspx

StreamWriter ドキュメントはこちらにあり、リーダーとライターの両方を使用する例が下部にあります。

http://msdn.microsoft.com/en-us/library/system.io.streamwriter.aspx

すべてのメソッドには論理名があり、対応する C++ よりも実装が簡単です。

case "A":の代わりにケースを使用する必要があるため、スイッチがコンパイルエラーを引き起こしていると思いcase A:ます そこにリテラルを入れると、文字列比較が行われます。それがローカル変数の名前でない限り、それは A が何であるかを理解していません。

編集: ファイルを読み取るためのサンプル コード。

// we need to alloc/init the streams inside for using blocks so they're properly disposed of
List<string> grades = new List<string>();
using (StreamReader inFile = new StreamReader("rec.in"))
{
     string line;
     while ((line = inFile.ReadLine()) != null)
     {
         string[] tokens = line.Split(' '); // split line on whitespace
         if (tokens.Length > 7)
             grades.Add(tokens[7]);
     }
}

using (StreamWriter outFile = new StreamWriter("rec.out"))
{
      foreach (string s in grades)
          outFile.WriteLine(s);
}

上記で使用している手法は完全に必要というわけではありません。たとえば、StreamReaders 内で使用して StreamWriter をネストし、同じスコープ内で書き込みを行うことができます。C# バージョンでは、ファイルの内容を 1 行ずつループしています。ラインを取得するたびに、それをスペースで分割してサブコンポーネントを取得します。次に、文字の等級をリストに追加します。WriteLine改行は自動的に行われるため、出力文字列に改行は必要ありません。ファイルの読み取りを行った後、リスト内の各文字列をループして出力ファイルに書き込みます。

于 2013-05-28T23:00:42.390 に答える