使用vim,shell或python转换小数点

时间:2018-07-19 06:43:57

标签: python shell vim

我有一个.pl文件,其中包含非结构化标头和某些特定的X Y Z结构。标头中没有“。”。在那里。您可以在下面找到此文件的摘要:

Header (in total 29 lines)
ILINE
VRTX 1 545057.78564453125 3800905.201171875 -15000 
VRTX 2 545184.49072265625 3800765.451171875 -15000 
VRTX 3 545310.91650390625 3800625.970703125 -15000 
SEG 1 2 
SEG 2 3 
ILINE
VRTX 136 551295.84606933594 3799015.443359375 -15000 
VRTX 137 551293.82849121094 3798841.880859375 -15000 
VRTX 138 551290.57849121094 3798661.892578125 -15000  
SEG 136 137 
SEG 137 138 

我想要实现的是这样将X和Y值的小数点向左移动:

VRTX 1 5450.5778564453125 38009.05201171875 -15000 
VRTX 2 5451.8449072265625 38007.65451171875 -15000 
VRTX 3 5453.1091650390625 38006.25970703125 -15000

我认为正则表达式可能会有所帮助,但是我没有使用Python或Shell的经验。任何帮助表示赞赏。

6 个答案:

答案 0 :(得分:5)

复制和粘贴友好的vim解决方案

:g/VRTX/normal f.xhhP;xhhP

说明:

  • :g / {pattern} / command -在每个匹配行的模式上执行命令。在这种情况下,每条 VRTX
  • 普通-我们要执行的命令是普通模式命令
  • f。-查找当前行中的第一个点
  • xhhP -剪切此类字符,向左移动两次,粘贴
  • ; -查找下一个事件
  • xhhP -再次移动点

答案 1 :(得分:2)

您可以使用awk来执行此操作,这是单行命令,

awk '{for(i=1;i<=NF;i++)if(match($i,/[0-9][0-9]\./))$i=substr($i,0,RSTART-1)"."substr($i,RSTART,2)substr($i,RSTART+3)}1' input_file

简要说明,

  1. 扫描每条记录中的所有字段
  2. match($i,/[0-9][0-9]\./:检查是否有任何字段与正则表达式[0-9][0-9]\.匹配
  3. 因为awk会在RSTART中记录匹配案例的起点。我们可以使用substr函数和RSTART信息来重新生成文件,以满足您的要求。

答案 2 :(得分:2)

由于该问题上有一个vim标签:

/\.
qaqqanx2hi!<esc>@aq
@a
:%s/!/./g

假设文本中没有!,否则您必须用其他字符代替。当然,vim中还有其他解决方案,但这是我现在能想到的最简单的方法。

故障:

 /\.                  " searches every `.` in the file 
                      " (and "marks" them as searchresults)

qaqqanx2hi!<esc>@aq   " Our macro we use:
qaq                   " records an empty macro into register a 
                      " (This ensures the register is empty)
   qa                 " This starts recording a macro into register a again
     nx2hi!<esc>      " `n` jumps to the next search result,  
                      " `2hxhi!<esc>` inserts a `!` 2 chars left of where
                      " the `.` has been, and exits insert mode
                @a    " calls the macro at register `a`, since we emptied it,
                      " nothing happens yet, but once we save this macro it will
                      " be in register `a`. So it will call itself until it 
                      " reaches an abort conditions (no more `.` found in the
                      " text, thats why we replace `.` with `!` here, else
                      " the macro would move the `.` over and over to the left
                  q   " Stops recording the macro and saves it (to register `a`)

@a                    " calls the macro in register `a`

:%s/!/./g             " This just replaces all `!` in the file with `.`

可能的清洁解决方案:使用nowrapscan (感谢@Francesco)

/\.
:set nows
qaqqax3hpn@aq
@a
:set ws

注意:宏更改顺序有点。我们必须首先更改.的位置,然后跳转到下一个搜索出现位置,否则我们将错过第一次出现的位置,因为搜索不再包含所有内容。

注意:最好先保存ws的状态,然后再将其还原。但这仅在通用版本中很重要。

结论

复杂但灵活的解决方案。如果您不需要灵活,这里的其他vim解决方案会更容易(我不会判断其他解决方案)

答案 3 :(得分:1)

这是Python中的解决方案。首先,我们定义一个为我们移动小数的函数。

SEARCH = '.'
OFFSET = -2

def replacer(bits):
   if SEARCH in bits:
      loc = bits.index(SEARCH)+OFFSET
      return ''.join('{}.'.format(x) if k == loc-1 else x for k,x in enumerate(bits.replace('.','')))
   else:
      return bits

下一步,将其应用于行:

s = """Header (in total 29 lines)
ILINE
VRTX 1 545057.78564453125 3800905.201171875 -15000 
VRTX 2 545184.49072265625 3800765.451171875 -15000 
VRTX 3 545310.91650390625 3800625.970703125 -15000 
SEG 1 2 
SEG 2 3 
ILINE
VRTX 136 551295.84606933594 3799015.443359375 -15000 
VRTX 137 551293.82849121094 3798841.880859375 -15000 
VRTX 138 551290.57849121094 3798661.892578125 -15000  
SEG 136 137 
SEG 137 138"""

>>> for i in s.split('\n'): 
..   if i.startswith('VRTX'): 
..     print(' '.join(map(replacer, i.split(' '))))

VRTX 1 5450.5778564453125 38009.05201171875 -15000 
VRTX 2 5451.8449072265625 38007.65451171875 -15000 
VRTX 3 5453.1091650390625 38006.25970703125 -15000 
VRTX 136 5512.9584606933594 37990.15443359375 -15000 
VRTX 137 5512.9382849121094 37988.41880859375 -15000 
VRTX 138 5512.9057849121094 37986.61892578125 -15000  

答案 4 :(得分:1)

我的正则表达式解决方案

:%s,\v(\d\d)\.,.\1,g

\v ...... very magic to avoid many backslashes
(\d\d) .. regex group one
\. ...... literal dot
\1 ...... reference to regex group one

答案 5 :(得分:0)

import re
new_data = ''
for line in data.splitlines():
    if '.' in line:
        mod_line = ''
        for word in line.split():
            if '.' in word:
                try:
                    float(word)
                    word = re.sub(r'(\d\d)\.', r'.\1', word)
                except:
                    pass
            mod_line += word + ' '
        new_data += mod_line.rstrip() +'\n'
    else:
        new_data += line + '\n'

new_data = new_data.rstrip()
print (new_data)

输出

ILINE
VRTX 1 5450.5778564453125 38009.05201171875 -15000
VRTX 2 5451.8449072265625 38007.65451171875 -15000
VRTX 3 5453.1091650390625 38006.25970703125 -15000
SEG 1 2 
SEG 2 3 
ILINE
VRTX 136 5512.9584606933594 37990.15443359375 -15000
VRTX 137 5512.9382849121094 37988.41880859375 -15000
VRTX 138 5512.9057849121094 37986.61892578125 -15000
SEG 136 137 
SEG 137 138