【问题标题】:Extracting number from irregular value with python [duplicate]用python从不规则值中提取数字[重复]
【发布时间】:2018-12-18 09:19:18
【问题描述】:

我有如下数据:

Format,Message,time
A,gn@2 ab@1 yl@5 rd@20 pp@40,3
B,w:w23w4w5w6w7gn@3 gn@7 yl@20 ss@25 rd@50,21
C,cc@1 fgn@4 yl@9 rd@20,22
D,rg@1 fedsf@5 rww@10 yl@20 rd@26,30

我的预期结果是提取 gn,yl 和 rd 之后的数字

Format,Message,time,gn,yl,rd
A,gn@2 ab@1 yl@5 rd@20 pp@40,3,2,5,20
B,w:w23w4w5w6w7gn@3 an@7 yl@20 ss@25 rd@50,21,3,20,50
C,cc@1 fgn@4 yl@9 rd@20,22,4,9,20
D,rg@1 fedsf@5 rww@10 yl@20 rd@26,30,0,20,26

到目前为止,我能够获得 yl 和 rd,但我无法提取 gn 之后的数字。请注意,gn 元素可能在 gn 之前包含一些其他字符,并且在 gn@ 之后需要数字

def f(mess):
    p1 = mess.find('yl')
    p2 = mess.find('rd')
    b = mess[p1+3:].split(' ')[0]
    c = mess[p2+3:].split(' ')[0]
    return int(b),int(c)
id['vals'] = id['Message'].apply(f) #with this im able to get the numbers from yl and rd

【问题讨论】:

  • 我喜欢你的用户名
  • 对 gn 使用相同的逻辑和 p3 变量有什么问题?
  • 我尝试使用 p3,但由于 gn 元素的长度不同,它没有提取数字并最终提取了该值中的一些其他字符。我将更新我的问题,因为我的实际数据中的值要长得多。我缩短并更改了数据以尝试和咨询,以便我能理解逻辑
  • @SamMason 这比链接中提出的提取更多元素的问题更进一步

标签: python regex


【解决方案1】:

让我们逐步解决这个问题。

  1. 只获取您感兴趣的行。
  2. 删除可能对我们没有用的数据。
  3. 使用剩下的数据来提取信息。

假设我将输入存储在变量data 中,我需要将输出存储在名为final 的元组列表中。以下是我将如何解决这个问题。

useful = data.split('\n')[1:]  ## Step 1
code = [x[1].strip() for x in useful.split(',')] ## Step 2
gn_value = -1
yl_value = -1
rd_value = -1
for line in code:
    for each in line.split(' '): ## Step 3
        if 'gn@' in each:
            gn_value = int(each[each.find('gn@')+3:])
        elif 'yl@' in each:
            yl_value = int(each[each.find('yl@')+3:])
        elif 'rd@' in each:
            rd_value = int(each[each.find('rd@')+3:])
    final.append(gn_value, yl_value, rd_value)

注意:上述解决方案是在假设任何给定行中的任何值都没有多次出现的情况下开发的。

如果您有任何疑问,请告诉我。

【讨论】:

    【解决方案2】:

    尝试使用以下表达式:

    mess = 'gn@2 ab@1 yl@5 rd@20 pp@40'
    result = [ int(m.split('@')[1])  for m in mess.split() if m.split('@')[0] in ['gn', 'yl', 'rd'] ]
    

    【讨论】:

      【解决方案3】:

      使用正则表达式。

      演示:

      import re
      s = """A,gn@2 ab@1 yl@5 rd@20 pp@40,3,2,5,20
      B,w:w23w4w5w6w7gn@3 an@7 yl@20 ss@25 rd@50,21,3,20,50
      C,cc@1 fgn@4 yl@9 rd@20,22,4,9,20
      C,cc@1 yl@9 rd@20,22,4,9,20"""
      
      for line in s.splitlines():
          gn = re.search(r"gn@(.?\S)", line)
          if gn:
              gn = gn.group(1)
      
          yl = re.search(r"yl@(.?\S)", line)
          if yl:
              yl = yl.group(1)
      
          rd = re.search(r"rd@(.?\S)", line)
          if rd:
              rd = rd.group(1)
          print(gn, yl, rd)
      

      输出:

      2 5 20
      3 20 50
      4 9 20
      None 9 20
      

      【讨论】:

      • 快速提问!如果假设我总共有 1000 行数据并且可能有 20% 的行没有这个 gn 元素,这会起作用吗,因为我尝试使用你的方法,它实际上显示了“nonetype”对象没有属性的错误'group' 所以我意识到实际上有一些带有 gn 元素的行
      • 您需要添加一个检查条件来处理它。更新片段
      • 您能指导我迈出这一步吗?
      【解决方案4】:

      我想我也会添加我的变体

      mess = """
      A,gn@2 ab@1 yl@5 rd@20 pp@40,3
      B,w:w23w4w5w6w7gn@3 gn@7 yl@20 ss@25 rd@50, 21
      C,cc@1 fgn@4 yl@9 rd@20, 22
      """
      
      for row in mess.strip().splitlines():
          print("ROW:", row)
          for col in row.split(" "):
              try:
                  k, v = col.split('@')
                  print("%s=%d" % (k[-2:], int(v.split(',', 1)[0])))
              except:
                  print("leftover=%s" % col)
          print()
      

      这会产生:

      ROW: A,gn@2 ab@1 yl@5 rd@20 pp@40,3
      gn=2
      ab=1
      yl=5
      rd=20
      pp=40
      
      ROW: B,w:w23w4w5w6w7gn@3 gn@7 yl@20 ss@25 rd@50, 21
      gn=3
      gn=7
      yl=20
      ss=25
      rd=50
      leftover=21
      
      ROW: C,cc@1 fgn@4 yl@9 rd@20, 22
      cc=1
      gn=4
      yl=9
      rd=20
      leftover=22
      

      无论您是否有多个重复的键或值,我都可以很容易地将它们推送到列表中:) 不需要多个条件和挑选。所有 key=value 对都可以访问。

      【讨论】:

        猜你喜欢
        • 2019-05-21
        • 1970-01-01
        • 1970-01-01
        • 2021-05-19
        • 1970-01-01
        • 2020-07-13
        • 2019-12-22
        • 2019-06-25
        • 2021-09-08
        相关资源
        最近更新 更多