小さくない、長すぎないテキストに収まる、要素記号の小さな有限集合(私は最後の計数で118と考える)があります文字列。 Fortranはテキスト処理のための最良の言語ではありません(私はPerlとSNOBOLがそれに対抗するようにします...)しかし、現代のFortranは少し改善しています。
次のコードに基づいていくつかの前提があります。まず、大文字と小文字を混在させて要素シンボルを入力することを期待します。大文字小文字を修正することはできますが、この例では、ユーザー入力の最初の文字が大文字ではなく、2番目の文字が空白または小文字でない場合、エラーをスローすることにしました。これは、Fortran 95の言語に追加されたverify
組み込み関数を使用して行われます(これは文字通り初めて使用したときのものです)。
intrinsicは、1より大きい文字列の中で部分文字列の最初の一致の開始位置を指定します。一致しない場合は0を返します。
elblob
文字列には、すべての要素シンボルがアンダースコアで区切られています。単一文字要素は、character(len=2)
変数に一致する末尾のスペースを保持します。 elblob
の前に2つのアスタリスクが付いているので、すべての要素が3で割り切れる文字から開始します。これは、原子番号について知っているものを利用する魔法の愚かなビットです.1から118までの範囲を完全に埋めるユニークで逐次的な整数です。
elseek
の最初の文字がスペースでないことを保証するために、恐らく問題ではないもう一つのビットは、adjustl()
の使用です。 Fortranのread()
の仕組みのせいではないかもしれませんが、私は妄想的ですので、そこに入れてください。最悪の場合は何もしないで数サイクルを燃やすことです。それを取り出して何が起こるかを見てください。
stray '_'と '*'を忘れないようにユーザー入力を確認することで、要素シンボルが正しく一致し、index()
によって返された一致位置を実際の原子番号に分割することができます3つ。カーボンの検索文字列はFortranの固定長文字列の効果である「C」ではなく「C」であるため、誤って一致することはありません。 elseek
がcharacter(len=:), allocatable
と定義されている場合、問題が発生する可能性がありますが、ダミーの古い固定長のスペースが埋め込まれた文字列を使用することによって、ダムの古い動作を使用することができます。
!> Return an element's atomic number based on its symbol.
program elements
use iso_fortran_env, only: input_unit, output_unit
implicit none
character(len=*), parameter :: alpha_u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
character(len=*), parameter :: alpha_l = 'abcdefghijklmnopqrstuvwxyz'
character(len=*), parameter :: elblob = &
'**H _He_Li_Be_B _C _N _O _F _Ne_Na_Mg_Al_Si_P _S _Cl_Ar_K _Ca_Sc_' &
// 'Ti_V _Cr_Mn_Fe_Co_Ni_Cu_Zn_Ga_Ge_As_Se_Br_Kr_Rb_Sr_Y _Zr_Nb_Mo_' &
// 'Tc_Ru_Rh_Pd_Ag_Cd_In_Sn_Sb_Te_I _Xe_Cs_Ba_La_Ce_Pr_Nd_Pm_Sm_Eu_' &
// 'Gd_Tb_Dy_Ho_Er_Tm_Yb_Lu_Hf_Ta_W _Re_Os_Ir_Pt_Au_Hg_Tl_Pb_Bi_Po_' &
// 'At_Rn_Fr_Ra_Ac_Th_Pa_U _Np_Pu_Am_Cm_Bk_Cf_Es_Fm_Md_No_Lr_Rf_Db_' &
// 'Sg_Bh_Hs_Mt_Ds_Rg_Cn_Nh_Fl_Mc_Lv_Ts_Og'
character(len=2) :: elseek
character(len=1) :: c
integer :: atomic_number
404 format("Sorry, I couldn't find ", '"', A, '"')
200 format("The element ", A, " has an atomic number of ", I0)
500 format('"', A, '" must be ', A, ' case letter')
continue
write(output_unit, '(A)') "Give me an element's symbol " &
// "(like H or Na)"
read(input_unit, '(A2)') elseek
! Left-justify; eliminates any leading space
! (Q: is leading space even possible?)
elseek = adjustl(elseek)
c = elseek(1:1)
if (verify(c, alpha_u) > 0) then
write(output_unit, 500) c, 'an upper'
stop(1)
end if
c = elseek(2:2)
if (verify(c, alpha_l // ' ') > 0) then
write(output_unit, 500) c, 'a lower'
stop(2)
end if
atomic_number = index(elblob, elseek)
if (atomic_number < 1) then
write(output_unit, 404) elseek
else
atomic_number = atomic_number/3
write(output_unit, 200) elseek, atomic_number
end if
end program elements
とにかく、私はこのすべてを30秒間テストしました。安全上重要なものには使用しないでください。これが宿題のためのものであれば、コードを読んで理解し、それをあなた自身のものとして書き直して、Turnitinにフラグを立てないようにしてください。
これは最も堅牢なソリューションではありませんが、短くてシンプルで、書かれた要件を満たしています。ハッシュテーブル、検索ツリー、または文字列より複雑なデータ構造は必要ありません。それはFORTRAN77の下で動作するためにそれを愚かにすることはあまりありませんが、その方法は狂気です...
私は複雑さのためのあなたのメートル法がここに何であるか分かりません。コードの行?読みやすさ?最終的に118種類の2文字の文字列に対して118種類の異なるパラメータを指定する必要があります。 – Ross
読みやすさは一つの懸念事項です。ちょうど 'case'構造は考えるのは簡単ですが、もっと速く、より読み易い方法があります。私は自分自身で思いつくことができません。 – Kurzd