平成30年秋期試験午後問題 問11

午前試験免除制度対応!基本情報技術者試験のeラーニング【独習ゼミ】

問11 ソフトウェア開発(Java)

次のJavaプログラムの説明及びプログラムを読んで,設問1,2に答えよ。
(Javaプログラムで使用するAPIの説明は,こちらを参照してください。)

〔プログラムの説明〕
 図1のように,文書の書式を表すひな形に置換表を適用して,出力文書を得るプログラムである。
pm11_1.png
  • ひな形は,0個以上の置換指示と,0個以上のそのまま出力される置換指示以外の部分が連なるテキストである。
     置換指示は,キー名称を < と > で囲ったものである。ひな形中で,< と > は,置換指示としてキー名称を囲う用途にだけ使用できる。
  • 置換表は,キー名称とこれに対応する文字列の並びとの組みを一つ以上記述したテキストであり,それぞれの組みは,次の形式で記述する。

      "キー名称":[文字列の並び]

     組みを二つ以上記述するときは,コンマで区切る。
     文字列の並びには,置換に用いる文字列(以下,置換用文字列という)を二重引用符で囲んだものを一つ以上記述する。置換用文字列を二つ以上記述するときは,コンマで区切る。例えば,置換用文字列が二つである場合は,次の形式で記述する。

      "キ一名称":["置換用文字列","置換用文字列"]

  • ひな形に置換表を適用すると,ひな形中の<キ一名称>は,次の規則に従って置換される。
    1. 置換表のキー名称に対応する文字列の並びに含まれる置換用文字列が一つだけのときは,その置換用文字列で置換される。
    2. 置換表のキー名称に対応する文字列の並びに含まれる置換用文字列が二つ以上あるときは,各置換用文字列の間に改行を挟んだ上で,並び順に連結してできる文字列で置換される。
     図1の例では,置換表中のキー名称 名前 に対応する文字列の並びに含まれる置換用文字列は 情報太郎 だけなので,ひな形中の<名前>は,情報太郎 に置換される。
     置換表中のキー名称 明細 に対応する文字列の並びには,置換用文字列として メモリ ; 5,000円 と HDD ; 9,000円 とが含まれるので,ひな形中の<明細>は, メモリ ; 5,000円⏎HDD ; 9,000円 (⏎は改行)に置換される。
 このプログラムでは,ひな形を,0個以上の置換指示と0個以上の置換指示以外の部分が連なる文字ストリームとして扱う。個々の置換指示及び個々の置換指示以外の部分をフラグメントと呼ぶ。
 インタフェース Fragment は,フラグメントを表す。
 クラス Replacer は,置換指示を表す。
 クラス PassThrough は,置換指示以外の部分を表す。
 クラス TemplateParser のメソッド parse は,ひな形を表す文字ストリームからフラグメントのリストを構築し,クラス Template のインスタンスを生成して返す。ひな形に誤りはないものとする。
 クラス Template は,ひな形をフラグメントのリストとして保持する。メソッド apply は,ひな形に置換表を適用して,出力文書を文字列で返す。置換表には,このひな形に含まれるキー名称とそれに対応する文字列の並びが含まれているものとする。
 クラス ReplacementTableParser のメソッド parse は,置換表を表す文字ストリームから,キー名称とそれに対応する文字列の並びのマップを構築して,返す。置換表に誤りはないものとする(プログラムは省略)。
 クラス TemplateTester はテスト用のプログラムである。テキストファイル template.txt が図1のひな形と同じ内容であって,テキストファイル replacementTable.txt が図1の置換表と同じ内容であるとき,実行結果は図1の出力文書と同じになる。

pm11_2.png

設問1

プログラム中の に入れる正しい答えを,解答群の中から選べ。
a に関する解答群
  • extends
  • interface
  • implements
  • throws
b,c に関する解答群
  • Fragment(buf)
  • Fragment(c)
  • PassThrough(buf)
  • PassThrough(c)
  • Replacer(buf)
  • Replacer(c)
d に関する解答群
  • fragmentList
  • new Template(buf)
  • new Template(fragmentList)
  • new Template(reader)
e に関する解答群
  • fragment
  • fragmentList
  • sb
  • table
解答選択欄
  • a:
  • b:
  • c:
  • d:
  • e:
  • a=
  • b=
  • c=
  • d=
  • e=

解説

aについて〕
〔プログラム2〕は Replacer クラス、〔プログラム3〕は PassThrough クラスです。
クラスがインタフェースを実装する場合は implements キーワードを使用します。

a=ウ:implements

bcについて〕
〔プログラム4〕TemplateParser クラスの空欄です。
TemplateParser クラスの parse メソッドはひな形を1文字ずつ読み込み、解析しながらフラグメントのリストを構築します。読み込んだ文字は buf に連結しながら保持しています。

読み込んだ文字列が < の場合と > の場合、フラグメントのリストに新しいインスタンスを生成し、buf を新しく生成しています。
fragmentList は List として宣言されています。よって、リストには Fragment 型のみ格納できます。しかし、Fragment はインタフェースのため new によってインスタンス化できません。new でインスタンス化できるのは Fragment インタフェースを実装しているクラス、つまり Replacer あるいは PassThrough のどちらかになります。

この時点で「ア」及び「イ」は除外されます。

続いて Replacer と PassThrough のソースコードを確認します。
コンストラクタは CharSequence 型の引数を1つ受け取る実装になっています。よって、引数の型が異なる「エ」と「カ」は除外されます。
ちなみに StringBuilder 型の buf ですが、午後問題P75に「char 値の可変のシーケンスを表す。インタフェース CharSequence を実装する」と明記されており、コンストラクタの引数に渡せます。

残りは「ウ」と「オ」です。

TemplateParse のswitch文を確認します。
< の場合とは、この文字以降は置換指示を表す事を意味します。つまり、それまで buf に溜め込んでいた文字は置換指示以外の部分です。よって PassThrough クラスのインスタンスを生成します。
反対に > の場合とは、この文字までは置換指示で、それ以降は置換指示以外を表します。つまり、それまで buf に溜め込んでいた文字は置換指示です。よって Replacer クラスのインスタンスを生成します。

b=ウ:PassThrough(buf)
 c=オ:Replacer(buf)

dについて〕
TemplateParse クラスの parse メソッドの戻り値です。
問題文より、parse メソッドの戻り値は Template 型なので、Template 型のインスタンスを返す必要があります。

この時点で、型が違う「ア」は誤りとわかります。

Templateクラスは〔プログラム5〕に記載されており、コンストラクタは、
Template(List fragmentList) {
  this.fragmentList = fragmentList;
}
と書かれています。このため、引数の型が異なる「イ」「エ」は除外されます。よって、残った「ウ」が正解です。

d=ウ:new Template(fragmentList)

eについて〕
〔プログラム5〕Template クラスの apply メソッドの空欄です。
sb.append(fragment.replace(e));
ソースコードより、該当部分は Fragment インタフェースの replace メソッドの引数になっているとわかります。

〔プログラム1〕を確認すると、
String replace(Map<String, List<String>> table);
と定義されています。つまり、Map<String, List<String>> 型を渡せば良いわけです。

apply メソッドに該当のインスタンスがあるかソースコードを確認すると、引数に table という変数名で渡されていることがわかります。よって、eには型が同じである table が入ります。それ以外の選択肢は型が異なるため誤りです。

e=エ:table

設問2

次の記述中の に入れる正しい答えを,解答群の中から選べ。

 < と > は,置換指示としてキー名称を囲う用途以外では,ひな形中で使用することができない。そこで,これらの文字を他の用途でも使用できるように,次の2行をプログラム4のクラス TemplateParser の α の位置に挿入した。これによって,\ に続く1文字( \ が複数個連続するときは奇数個目に続く1文字)は,置換指示以外の部分やキー名称の一部として扱われる。ここで,続く1文字は必ず読めるものとする。
pm11_3.png
f に関する解答群
  • break
  • buf.append((char) c)
  • buf.append((char) c); break
  • buf.append((char) reader. read())
  • buf.append((char) reader. read()); break
解答選択欄
  • f:
  • f=

解説

fについて〕
\ (バックスラッシュ)に続く1文字が < や > のときに、置換指示として解析しないようにするためのコード追加です。よって、\ が読み込まれた場合、その次の1文字を読み込んで buf へ追加する処理にします。

1文字を読み込む方法は、Reader クラスの read メソッドです(午後問題P74にも書かれています)。
whileのループ条件に書かれている reader.read() の戻り値を char 型にキャストし、buf に格納するようにします。

ここで、switch文の動作について注意があります。各case文で break を書かない場合、次のcase文も処理します。

選択肢「エ」のように、breakを書かない場合、
case '\\' :
  buf.append((char) reader.read());
default :
  buf.append((char)c);
となり、defaultに記述された部分も処理してしまいます。これをフォールスルー(fall through)と呼びます。今回の場合、defaultの部分が処理されると \ の次の1文字を二重で buf に追加してしまうことになるため、break するコードが正しいです。

f=オ:buf.append((char) reader. read()); break
  • 文字が格納されないため誤りです。
  • c は現在読み込んだ1文字を示すため、\ を格納してしまいます。
  • 「イ」と同様の理由で誤りです。
  • \ の次の1文字を二重で buf に追加してしまうため誤りです。

Pagetop