2012-07-08 46 views
0

我试图在一个文件中将lat和long中的位置解析为另一个文件中的几个命名字段。比较最近匹配的两个文件中的字段

我有一个文件,它是这样的..

    f1--f2--f3--------f4--------    f5--- 
R    20175155 41273951N078593973W    18012    
R    20175156 41274168N078593975W    18000    
R    20175157 41274387N078593976W    17999    
R    20175158 41274603N078593977W    18024    
R    20175159 41274823N078593978W    18087 

每个字符是在一个特定的地方,所以我需要定义基于字符的字段。

f1 char 18-21; f2 char 22 - 25; f3 char 26-35; f4 char 36-45; f5字符62-66。

我有另一个更大的csv文件,其中有11,12和13字段对应于f3,f4,f5。

awk -F',' '{print $11, $12, $13}' 
41.46703821 -078.98476926 519.21 
41.46763555 -078.98477791 524.13 
41.46824123 -078.98479015 526.67 
41.46884129 -078.98480615 528.66 
41.46943371 -078.98478482 530.50 

我需要找到最匹配的文件1场1 & & 2文件2场11 & & 12;

当最接近的匹配被发现我需要从文件1插入字段1,2,3,4,5到文件2字段16,17,18,19,20

正如可以看到格式略有不同。文件1个发生故障这样的..

文件1个

f3-------f4-------- 

DDMMSSdd DDDMMSSdd 

41273951N078593973W 

文件2

f11-------- f12--------- 

DD dddddddd DDD dddddddd 

41.46703821 -078.98476926 

N表示f3是一个正数,W表示f4是一个负数。

我改变文件1 SED,雷人的内衬的伟大工程.. (更好的办法???)

cat $file1 |sed 's/.\{17\}//' |sed 's/\(.\{4\}\)\(.\{4\}\)\(.\{9\}\)\(.\)\(.\{9\}\)\(.\)\(.\{16\}\)\(.\{5\}\)/\1,\2,\3,\4,\5,\6,\8/'|sed 's/\(.\{10\}\)\(.\{3\}\)\(.\{2\}\)\(.\{2\}\)\(.\{2\}\)\(.\{3\}\)\(.\{3\}\)\(.\{2\}\)\(.*\)/\1\2,\3,\4.\5\6\7,\8\9/'|sed 's/\(.\{31\}\)\(.\{2\}\)\(.*\)/\1,\2.\3/' 

2017,5155,41,27,39.51,N,078,59 ,39.73,W,18012
2017,5156,41,27,41.68,N,078,59,39.75,W,18000
2017,5157,41,27,43.87,N,078,59,39.76,W ,17999
2017,5158,41,27,46.03,N,078,59,39.77,W,18024
2017,5159,41,27,48.23,N,078,59,39.78,W,18087

现在我必须转换格式.. (已解决此问题(见下文) - 问题 - 数字四舍五入太远。我需要有至少六个小数位)

awk -F',' '{for (i=1;i<=NF;i++) {if (i <= 2) printf ($i","); else if (i == 3&&$6 == "S") printf("-"$3+($4/60)+($5/3600)","); else if (i == 3&&$6 == "N") printf($3+($4/60)+($5/3600)","); else if (i == 7&&$10 == "W") printf("-"$7+($8/60)+($9/3600)","); else if (i == 7&&$10 == "E") printf($7+($8/60)+($9/3600)","); if (i == 11) printf ($i"\n")}}' 

2017,5155,41.461,-78.9944,18012
2017,5156,41.4616,-78.9944,18000
2017,5157,41.4622, - 78.9944,17999
2017,5158,41.4628,-78.9944,18024
2017,5159,41.4634,-78.9944,18087

这是我在哪里。

解决了这个 * 我需要的数字格式有从这个公式至少6位小数。 *

的printf($ 3 +($ 4/60)+($3600分之5)) 添加 “%.8f”

的printf( “%8F”,$ 3 +($ 4/60 )+($ 5/3600))

下一期将与匹配字段文件1 f3和f4到文件2中最接近匹配的f11和f12。

有什么建议吗?

然后我将需要计算字段之间的距离。

在Excel中formuls会是这样..

=ATAN2(COS(lat1)*SIN(lat2)-SIN(lat1)*COS(lat2)*COS(lon2-lon1), SIN(lon2-lon1)*COS(lat2)) 

我可以用什么来该计算?

* UPDATE --- 我正在寻找匹配位置的短距离。我正在考虑应用像毕达哥拉斯定理那样简单的东西来进行最接近的比赛。也许甚至使用更少的小数位。它的速度要快很多倍。 也许是这样的.. *

x = (lon2-lon1) * Math.cos((lat1+lat2)/2); 

y = (lat2-lat1); 

d = Math.sqrt(x*x + y*y) * R; 

然后最终文件被更新后,我可以做更大的精度所需的大量计算。

感谢

+0

我不认为你可以用'awk'获得你需要的精度。但是,'bc'应该提供“任意精度”以及一个好的几何函数库。我建议你将问题分为“如何规范化这两种文件格式”和“如何在数字在文件中时用'bc'进行计算”。也许你已经可以自己解决这两个问题了。 – tripleee 2012-07-08 08:17:53

+0

也许这篇文章可以帮助:http://www.linuxjournal.com/magazine/work-shell-calculating-distance-between-two-latitudelongitude-points – user1498339 2012-07-08 08:25:56

+0

@tripleee:在AWK中查看'OFMT'和'CONVFMT'变量。你不能像'bc'那样得到任意的精度,但你肯定可以为这个应用程序获得足够的小数位数。 – 2012-07-08 10:45:47

回答

0

执行最接近的匹配后,你不能做的距离计算:最近由距离值的比较定义。 Awk可以评估你想要的公式(看起来像大圆距离?)。看看this chapter看看你需要什么。

最大的问题是找到最近的匹配。编写一个awk脚本,它接受一行文件1并输出文件2中的行与一个额外的列。该列是根据您的距离公式计算一对点之间的距离。如果您按数字排序该文件(sort -n),那么您最接近的匹配位于顶部。然后你需要一个脚本,它循环遍历文件1中的每一行,调用你的awk脚本,使用head -n1来拉出最接近的匹配,然后以你想要的格式输出它。

这在bash和awk中都是可行的,但是它会是Python中更简单的脚本。取决于你喜欢哪一个。

相关问题