4年に一度のスポーツの祭典 全競技速報中

入力した数字を英単語に変換するというプログラムなのですが、
仕様は
①10進数値を入力
a,0から99までの数値とする
b,範囲外の場合はエラー表示する
②英単語に変換
③出力する

①は組めたのですが②が全く分かりません。とんでもなく長くなりそうな気がしますし、そもそも「1」と入力したら「one」で「2」と入力したら「two」と表示させることは出来るのですか?
C#はまだまだ初心者なので分かりやすいヒントが知りたいです。

gooドクター

A 回答 (3件)

> とんでもなく長くなりそうな気がします



長くなりますね。フツーだと。

その「長くなりそうだ」と言うのが「勘」で、大概そういう勘って正しいんですよ。
プログラミングに向いてる人ってのは、結局、

「その長くなりそうなブツを如何に短く書くか」

腐心出来る人なんです。短く書ければ成功、そうじゃなきゃ失敗、で、その短く書く事に挑戦する事を楽しめる人なんです。

このケースだと変換ルーティンをマトモに考えるとクソ長くなるのは一発で分かる。そして文字列を準備しておかなきゃならないのは自明です。
後者はしょうがないとしても、数値はどう英語で表現してるのか・・・・・・。実は、仮にこれが「日本語」だったら割に簡単なんだけど、「英語」ってのがクセモノなんですよ(笑)。英語の知識でルールらしきモノをでっち上げなきゃならない。
結局、キモは数値と英名の対応ルールです。これをif文だけでデッチ上げるのは大変です。
そこで、配列を使います。

全然C#は分からないんで、例によってC#に一番似てると思われるJavaを使ってみます(多分C言語よかJavaに近いでしょう)。

// ここから

import java.util.Scanner;

public class Main {
 public static void main(String[] args) {
  // 一の位の配列
  String[] digits = {"", "one",
          "two", "three",
          "four", "five",
          "six", "seven",
          "eight", "nine"};
  // 十の位の配列
  String[] tensPlace = {"", "ten",
            "twenty", "thirty",
            "forty", "fifty",
            "sixty", "seventy",
            "eighty", "ninety"};
  // 十代
  String[] teens = {"", "eleven",
          "twelve", "thirteen",
          "fourteen", "fifteen",
          "sixteen", "seventeen",
          "eighteen", "nineteen"};
  int n = new Scanner(System.in).nextInt(); // 整数の入力
  if (n < 0 || n > 99) { // 範囲外
   System.out.println("エラー"); // 例外を投げても良いかも
  } else if (n > 10 && n < 20) { // 十代
   System.out.println(teens[n-10]);
  } else if (n == 0) { // 入力が0だった場合
   System.out.println("zero");
  } else {
   int r = n % 10; // 一の位
   int q = (int)(n - r)/10; // 十の位
   System.out.println(tensPlace[q] + " " + digits[r]);
  }
 }
}

// ここまで

結局、何がメンド臭いか、と言うと、英語での数値表現の場合、微妙に十二進法が混ざってる事なんですよね。
幸いな事にそこが絡んでるのは十代のトコロだけ。だからそこの英語表現だけをまずは括りだす、と言うのが一つ目の戦略(フランス語だったら多分僕もぶん投げてる・笑)。
あとは、十の位をどう表現してるのか、の配列と一の位の配列を準備します。
・・・まぁ、もっと細かくしてもいいけど、例えばteenが付く数値と接頭辞の関係を記述・・・とか言うのも考えられますが、現実的じゃないでしょう。我々は言語学者じゃないですし、そもそもC系の言語は元々そういうのが苦手。そういうのはシンボルを相手に自在にいろいろやれる言語(Lisp)とか、性器もとい正規表現が得意な言語(Perl)なんかに任せておけば良い。少なくとも、ルールが

1. 10 < n < 20 のnの表現
2. それ以外

で済むのなら現実的に充分実装出来る範疇です。
じゃあ、あとはどう配列を設計するか、ってだけになる。
ここでは例えば

String[] digits = {"", "one",
        "two", "three",
        "four", "five",
        "six", "seven",
        "eight", "nine"};

みたいに設計してます。
何で配列の先頭を""としてるのか、と言うと

1. 配列の要素番号と、単純には一桁の入力の数値を対応させる為
2. ゼロ項目が""だったら一桁の数値と二桁の数値で場合分けする必要がなくなる

からです。
例えば入力が3だった場合、単に配列digitsから3番目の要素を探してくれば良い。例: digits[3] ==> "three"
お忘れかもしれませんが、配列は0から数えたりするんで、一個ズレてるんですよね。
もちろん

String[] digits = {"one",
        "two", "three",
        "four", "five",
        "six", "seven",
        "eight", "nine"};

してn = 3の時、digits[n-1] => "three"でも良いんですが、コード書いてる最中に間違えるかもしれんですし、いずれにせよ、C言語由来(いや、Pascalか?)の「良くある手」です。そしてより重要なのは2番目、です。
例えば94と入力された時、我々はそれを9と4に分解せんとイケない。
そして十桁ではtensPlace[9] => "ninty"、一桁ではtensPlace[4] => "four"、合わせてninty fourと言う文字列を得られます。
でもこの入力システムを汎用的に使うとすると、一桁の数値が入力されると、例えば

3が入力される => 3は0と3に分解される

となります。十桁は0、一桁は3、と。
そうすると、十桁の配列の0番目は""なんで結果表示に影響を与えないんですよ。残りの3はdigit[3]に適用されて"three"を返してくる。つまり、単純に"three"だけになるんですね。
データ型の方にこの仕組み、つまり、0番目を""にする、と言う設計をしておかないと、場合によっては数値が10以下の場合、数値が20以上の場合、とif節を増やしてメンド臭い事になる。
その辺の影響を踏まえると各配列の第0要素は""にしておいた方が都合が良い、のです。仮に0が入力されたら、その時だけは例外として"zero"を表示させた方が結果紛れがないんですよね。
と言うわけで・・・宿題だとしたら、目的は「データの上手な設計の仕方・入門編」ってトコかな。上手く配列を設計出来たりすれば、のちのプログラムを書くのが滅茶苦茶ラクになりますよ、と。そう言った題意の問題だと思います。
    • good
    • 1
この回答へのお礼

丁寧な説明、ありがとうございます!
配列について覚えることができました。
短くすることに挑戦し、それを楽しむように今後も頑張ります。

お礼日時:2021/06/10 14:52

using System;



namespace ConsoleApp1
{
  class Program
  {
    static void Main(string[] args)
    {
      var input = Console.ReadLine();
      int value;
      if (!int.TryParse(input, out value))
      {
        Console.WriteLine("エラー");
        Console.ReadLine();
        return;
      }
      if (value < 0 || value > 99)
      {
        Console.WriteLine("エラー");
        Console.ReadLine();
        return;
      }

      Console.WriteLine(value.ToEnglish());
      Console.ReadLine();
    }
  }

  static class IntExtensions
  {
    /// <summary>
    /// 与えられた99以下の数値を英語に変換します。
    /// </summary>
    /// <param name="value">値。</param>
    /// <returns></returns>
    public static string ToEnglish(this int value)
    {
      var onesPlace = new[] { "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
      var lessTwenty = new[] { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
      var tensPlace = new[] { "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };

      if (value == 0)
      {
        return "zero";
      }
      if (value < 10)
      {
        return onesPlace[value];
      }
      if (value > 9 && value < 20)
      {
        return lessTwenty[value % 10];
      }

      return $"{tensPlace[value / 10]} {onesPlace[value % 10]}";
    }
  }
}
    • good
    • 0
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

gooドクター

このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング