从文本文件中提取值的Pythonic方法
我有一个旧软件生成的输出文件,内容如下。我想从中提取一些数值,比如把一个叫 direct_solar_irradiance
的变量设置为 648.957
,把 target ground pressure
设置为 1013.00
。
到目前为止,我一直是逐行提取数据并处理,像下面这样(为了提取不同的值,这个过程重复了很多次):
values = lines[97].split()
self.irradiance_direct, self.irradiance_diffuse, self.irradiance_env = values
不过,我发现当选择某些参数时,输出中会多出一些行。这意味着,第97行可能不再包含我需要的值。
那么,有没有什么好的Python方法来提取这些值呢?因为在某些情况下,输出中可能会增加额外的行。我想我需要在文件中搜索已知的文本,然后提取与之相关的数字,但我想到的办法都很笨重。
所以:
有没有简单的Python方法可以搜索这些字符串并提取我想要的值?
如果没有,还有其他合理的方法吗?(比如,有什么我不知道的很酷的文本文件解析库)。
******************************* 6sV version 1.0B ****************************** * * * geometrical conditions identity * * ------------------------------- * * user defined conditions * * * * month: 14 day : 1 * * solar zenith angle: 10.00 deg solar azimuthal angle: 20.00 deg * * view zenith angle: 30.00 deg view azimuthal angle: 40.00 deg * * scattering angle: 159.14 deg azimuthal angle difference: 20.00 deg * * * * atmospheric model description * * ----------------------------- * * atmospheric model identity : * * midlatitude summer (uh2o=2.93g/cm2,uo3=.319cm-atm) * * aerosols type identity : * * Maritime aerosol model * * optical condition identity : * * visibility : 8.49 km opt. thick. 550 nm : 0.5000 * * * * spectral condition * * ------------------ * * monochromatic calculation at wl 0.400 micron * * * * Surface polarization parameters * * ---------------------------------- * * * * * * Surface Polarization Q,U,Rop,Chi 0.00000 0.00000 0.00000 0.00 * * * * * * target type * * ----------- * * homogeneous ground * * monochromatic reflectance 1.000 * * * * target elevation description * * ---------------------------- * * ground pressure [mb] 1013.00 * * ground altitude [km] 0.000 * * * * plane simulation description * * ---------------------------- * * plane pressure [mb] 1013.00 * * plane altitude absolute [km] 0.000 * * atmosphere under plane description: * * ozone content 0.000 * * h2o content 0.000 * * aerosol opt. thick. 550nm 0.000 * * * * atmospheric correction activated * * -------------------------------- * * BRDF coupling correction * * input apparent reflectance : 0.500 * * * ******************************************************************************* ******************************************************************************* * * * integrated values of : * * -------------------- * * * * apparent reflectance 1.1287696 appar. rad.(w/m2/sr/mic) 588.646 * * total gaseous transmittance 1.000 * * * ******************************************************************************* * * * coupling aerosol -wv : * * -------------------- * * wv above aerosol : 1.129 wv mixed with aerosol : 1.129 * * wv under aerosol : 1.129 * ******************************************************************************* * * * integrated values of : * * -------------------- * * * * app. polarized refl. 0.0000 app. pol. rad. (w/m2/sr/mic) 0.000 * * direction of the plane of polarization 0.00 * * total polarization ratio 0.000 * * * ******************************************************************************* * * * int. normalized values of : * * --------------------------- * * % of irradiance at ground level * * % of direct irr. % of diffuse irr. % of enviro. irr * * 0.351 0.354 0.295 * * reflectance at satellite level * * atm. intrin. ref. background ref. pixel reflectance * * 0.000 0.000 1.129 * * * * int. absolute values of * * ----------------------- * * irr. at ground level (w/m2/mic) * * direct solar irr. atm. diffuse irr. environment irr * * 648.957 655.412 544.918 * * rad at satel. level (w/m2/sr/mic) * * atm. intrin. rad. background rad. pixel radiance * * 0.000 0.000 588.646 * * * * * * sol. spect (in w/m2/mic) * * 1663.594 * * * ******************************************************************************* ******************************************************************************* * * * integrated values of : * * -------------------- * * * * downward upward total * * global gas. trans. : 1.00000 1.00000 1.00000 * * water " " : 1.00000 1.00000 1.00000 * * ozone " " : 1.00000 1.00000 1.00000 * * co2 " " : 1.00000 1.00000 1.00000 * * oxyg " " : 1.00000 1.00000 1.00000 * * no2 " " : 1.00000 1.00000 1.00000 * * ch4 " " : 1.00000 1.00000 1.00000 * * co " " : 1.00000 1.00000 1.00000 * * * * * * rayl. sca. trans. : 0.84422 1.00000 0.84422 * * aeros. sca. " : 0.94572 1.00000 0.94572 * * total sca. " : 0.79616 1.00000 0.79616 * * * * * * * * rayleigh aerosols total * * * * spherical albedo : 0.23410 0.12354 0.29466 * * optical depth total: 0.36193 0.55006 0.91199 * * optical depth plane: 0.00000 0.00000 0.00000 * * reflectance I : 0.00000 0.00000 0.00000 * * reflectance Q : 0.00000 0.00000 0.00000 * * reflectance U : 0.00000 0.00000 0.00000 * * polarized reflect. : 0.00000 0.00000 0.00000 * * degree of polar. : nan 0.00 nan * * dir. plane polar. : -45.00 -45.00 -45.00 * * phase function I : 1.38819 0.27621 0.71751 * * phase function Q : -0.09117 -0.00856 -0.04134 * * phase function U : -1.34383 0.02142 -0.52039 * * primary deg. of pol: -0.06567 -0.03099 -0.05762 * * sing. scat. albedo : 1.00000 0.98774 0.99261 * * * * * ******************************************************************************* ******************************************************************************* ******************************************************************************* * atmospheric correction result * * ----------------------------- * * input apparent reflectance : 0.500 * * measured radiance [w/m2/sr/mic] : 260.747 * * atmospherically corrected reflectance * * Lambertian case : 0.52995 * * BRDF case : 0.52995 * * coefficients xa xb xc : 0.00241 0.00000 0.29466 * * y=xa*(measured radiance)-xb; acr=y/(1.+xc*y) *
5 个回答
如果你想要一个通用的解析库,可以看看pyparsing,不过在这个情况下可能有点过于复杂了。
看起来这个文件是按行排列的文本文件,而且文件大小也不大,所以最好的办法就是逐行读取,寻找能帮助你找到所需内容的文本。
你可以这样做:
lines = open('file.txt', 'r')
for n, line in enumerate(lines):
if 'direct solar irr. atm. diffuse irr. environment irr' in line:
values = lines[n+1].split() # after the next line after this one
self.irradiance_direct, self.irradiance_diffuse, self.irradiance_env = values
然后你可以根据需要添加更多的if语句来提取其他数据。不过如果数据量很大,你可能需要让代码更通用一些。(可以考虑用一个字典,把要匹配的文本作为键,匹配到时调用的函数作为值)。
你可能还想使用正则表达式来匹配行,这样可以更好地处理不同数量的空格。否则,空格多了一点或少了一点都会导致匹配失败。
要想找到一个更完整、可能更稳健的解决方案,我们需要使用一个解析器,这个解析器可以用自定义的语法来处理数据(比如pyparsing),或者使用某种基于状态机的处理器(比如TextFSM)。
不过,这两种选择看起来都不太容易用在这个输出上。一个可能更简单的办法是根据已知的标签来识别每一行,然后提取出需要的信息(正如其他人所建议的那样)。
实现这个有几种方法。我建议把“提取器”函数和已知的行标签对应起来,然后逐行检查并调用匹配的提取器。每个提取器函数会接收一行文本和一个上下文对象/字典作为参数,并根据需要向上下文中添加属性。可以参考一下https://gist.github.com/1035938的内容。
你可以自己创建一个小语言,也就是自动提取数据。我做了以下步骤来自动解析一个专有程序的输出。
# will match in the order written here
tokens = ["num_ref_frames", "Max QP", "Min QP", "Avg QP", "I4x4",
"I16x16", "SkipZero", "SkipMV", "16x16", "16x8", "8x16",
"8x8", "8x4", "4x8", "4x4"]
special = ["Quarterpel MVs"]
# this dictionary (hash-table) contains the search string from tokens array
# as well as an array where the first element is the field to extract to
# create matrix array. e.g. 0 = 1st field, 1 = 2nd field, 3 = 3rd field etc.
dict = {tokens[0]: [1], tokens[1]: [1], tokens[2]: [1], tokens[3]: [1],
tokens[4]: [2], tokens[5]: [2], tokens[6]: [2], tokens[7]: [2],
tokens[8]: [2], tokens[9]: [2], tokens[10]: [2], tokens[11]: [2],
tokens[12]: [2], tokens[13]: [2], tokens[14]: [2],}
然后我简单地遍历输入的每一行,检查每一行是否和token
的内容匹配;如果找到了匹配的内容,我就根据字典中的条目进行分割,以提取正确的字段。
上面的special
是用来处理一个特殊变量的,这个变量需要从多行中读取。
更新
你可以克隆git://gist.github.com/1037403.git
来获取代码的副本。
usage:
./parser.py all_dec.txt
希望这对你有帮助!