有一小部分有限的元素符号(我相信最后计数为 118 个)可以放入不太长的文本字符串中。Fortran 不是文本处理的最佳语言(我会让 Perl 和 SNOBOL 为之争辩……)但现代 Fortran 已经稍微改善了一些问题。
以下代码中有一些假设。首先,我们希望用户使用大小写混合输入元素符号。您可以更正大小写,但对于此示例,如果用户输入中的第一个字符不是大写并且第二个字符不是空格或小写,我决定只抛出错误。这是使用verify
在 Fortran 95 中添加到语言中的内在函数来完成的(这实际上是我第一次使用它)。
index()
内在函数将为您提供从 1 开始计数的较大字符串中子字符串的第一个匹配项的起始位置,如果未找到匹配项,则返回 0 。
该elblob
字符串包含由下划线分隔的每个元素符号。单个字母元素保留尾随空格以匹配character(len=2)
变量。前面有两个星号,elblob
因此每个元素都以可被三整除的字符开头。这是一个愚蠢的魔法,它利用了我们对原子序数的了解——它们是唯一的、连续的整数,完全填充了从 1 到 118 的范围(或者这些天的顶级元素)。
另一个可能解决非问题的偷偷摸摸的位是使用adjustl()
确保第一个字符elseek
不是空格。这可能不仅仅是因为 Fortran 的read()
工作方式,但我很偏执,所以我把它放在那里。它会做的最糟糕的事情是烧几个周期什么都不做。把它拿出来看看会发生什么。
通过对用户输入进行完整性检查以排除杂散的 '_' 和 '*',我们可以确保元素符号将正确匹配,并且我们可以通过将返回的匹配位置除以index()
3 来获得真正的原子序数。Carbon 不会意外匹配钙,因为 carbon 的搜索字符串是“C”,而不是“C”,这是 Fortran 固定长度字符串的效果。如果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 下工作并不需要太多,但那样就是疯狂......