【问题标题】:process a text file using various delimiters使用各种分隔符处理文本文件
【发布时间】:2015-11-07 10:04:07
【问题描述】:

我的文本文件(不幸的是)看起来像这样......

<amar>[amar-1000#Fem$$$_Y](1){india|1000#Fem$$$,mumbai|1000#Mas$$$}
<akbar>[akbar-1000#Fem$$$_Y](1){}
<john>[-0000#$$$_N](0){USA|0100#$avi$$,NJ|0100#$avi$$}

它包含客户名称和一些信息。顺序是……

文本字符串后跟列表、集合和字典

[] () {}

这不是与 python 兼容的文件,因此数据与预期不符。我想处理文件并提取一些信息。

amar 1000 | 1000  | 1000
akbar 1000  
john 0000  | 0100 | 0100

1)

之间的名称

2) 列表中 - 和 # 之间的数字

3 & 4) 在逗号和 | 之间的数字上拆分字典和#(这里可以有2个以上的条目)

我愿意使用任何最适合这项任务的工具。

【问题讨论】:

    标签: python awk sed grep


    【解决方案1】:

    由于语法相当复杂,您可能会找到合适的解析器作为最佳解决方案。

    #!/usr/bin/env python
    
    import fileinput
    from pyparsing import Word, Regex, Optional, Suppress, ZeroOrMore, alphas, nums
    
    
    name = Suppress('<') + Word(alphas) + Suppress('>')
    reclist = Suppress('[' + Optional(Word(alphas)) + '-') + Word(nums) + Suppress(Regex("[^]]+]"))
    digit = Suppress('(' + Word(nums) + ')')
    dictStart = Suppress('{')
    dictVals = Suppress(Word(alphas) + '|') + Word(nums) + Suppress('#' + Regex('[^,}]+') + Optional(','))
    dictEnd = Suppress('}')
    
    parser = name + reclist + digit + dictStart + ZeroOrMore(dictVals) + dictEnd
    
    for line in fileinput.input():
        print ' | '.join(parser.parseString(line))
    

    此解决方案使用pyparsing 库并运行产生:

    $ python parse.py file
    amar | 1000 | 1000 | 1000
    akbar | 1000
    john | 0000 | 0100 | 0100
    

    【讨论】:

      【解决方案2】:

      对于您的文件的一行:

      test='<amar>[amar-1000#Fem$$$_Y](1){india|1000#Fem$$$,mumbai|1000#Mas$$$}'
      

      将 之后的所有内容以获取名字

      echo $test | sed -e 's/<//g' | sed -e 's/>.*//g'
      

      获取所有 4 位字符套件:

      echo $test |  grep -o '[0-9]\{4\}'
      

      用你喜欢的分隔符替换空格

      sed -e 's/ /|/g'
      

      这将使:

      echo $(echo $test | sed -e 's/<//g' | sed -e 's/>.*//g') $(echo $test |  grep -o '[0-9]\{4\}') | sed -e 's/ /|/g'
      

      这将输出:

      阿马尔|1000|1000|1000

      用一个快速的脚本你得到它:your_script.sh input_file output_file

      #!/bin/bash
      
      IFS=$'\n' #line delimiter
      
      #empty your output file
      cp /dev/null "$2"
      
      for i in $(cat "$1"); do
          newline=`echo $(echo $i | sed -e 's/<//g' | sed -e 's/>.*//g') $(echo $i |  grep -o '[0-9]\{4\}') | sed -e 's/ /|/g'`
          echo $newline >> "$2"
      done
      
      cat "$2"
      

      【讨论】:

        【解决方案3】:

        以下 Python 脚本将读取您的文本文件并为您提供所需的结果:

        import re, itertools
        
        with open("input.txt", "r") as f_input:
            for line in f_input:
                reLine = re.match(r"<(\w+)>\[(.*?)\].*?{(.*?)\}", line) 
                lNumbers = [re.findall(".*?(\d+).*?", entry) for entry in  reLine.groups()[1:]]
                lNumbers = list(itertools.chain.from_iterable(lNumbers))
                print reLine.group(1), " | ".join(lNumbers)
        

        这将打印以下输出:

        amar 1000 | 1000 | 1000
        akbar 1000
        john 0000 | 0100 | 0100
        

        【讨论】:

        • sed/ shell 很好。 awk 很棒。但我接受这个解决方案,因为实际数据更复杂,我只能在使用这里显示的重新拆分数据后才能管理它。
        【解决方案4】:

        你可以使用正则表达式来捕捉参数

        样本:

        a="<john>[-0000#$$$_N](0){USA|0100#$avi$$,NJ|0100#$avi$$}"
        name=" ".join(re.findall("<(\w+)>[\s\S]+?-(\d+)#",a)[0])
        others=re.findall("\|(\d+)#",a)
        print name+" | "+" | ".join(others) if others else " "
        

        输出:

        'john 0000 | 0100 | 0100'
        

        完整代码:

        with open("input.txt","r") as inp:
             for line in inp:
                  name=re.findall("<(\w+)>[\s\S]+?-(\d+)#",line)[0]
                  others=re.findall("\|(\d+)#",line)
                  print name+" | "+" | ".join(others) if others else " "
        

        【讨论】:

          【解决方案5】:

          您可以将所有分隔符添加到FS 变量中的 和计数字段,例如:

          awk -F'[<>#|-]' '{ print $2, $4, $6, $8 }' infile
          

          如果大括号之间有两个以上的条目,则可以使用循环遍历所有字段,直到最后一个,例如:

          awk -F'[<>#|-]' '{ 
              printf "%s %s ", $2, $4
              for (i = 6; i <= NF; i += 2) { 
                  printf "%s ", $i 
              }
              printf "\n" 
          }' infile
          

          两个命令产生相同的结果:

          amar 1000 1000 1000 
          akbar 1000 
          john 0000 0100 0100
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-09-01
            • 1970-01-01
            相关资源
            最近更新 更多