【问题标题】:replace four digits pandas替换四位数熊猫
【发布时间】:2019-08-27 19:02:00
【问题描述】:
import pandas as pd
dataframe = pd.DataFrame({'Data' : ['The **ALI**1929 for 90 days but not 77731929 ', 
                                       'For all **ALI**1952  28A 177945 ', 
                                       'But the **ALI**1914 and **ALI**1903 1912',],
                          'ID': [1,2,3]

                         })

Data    ID
0   The **ALI**1929 for 90 days but not 77731929    1
1   For all **ALI**1952 28A 177945                  2
2   But the **ALI**1914 and **ALI**1903 1912        3

我的数据框看起来像我上面的。我的目标是用与**ALI** 关联的1929 或以下的任何数字替换单词OLDER。所以**ALI**1929 将是**ALI**OLDERALI**1903 也将是**ALI**OLDER**ALI**1952 将保持不变。来自How to extract certain length of numbers from a string in python?我试过了

dataframe['older'] = dataframe['Data'].str.replace(r'(?<!\d)(\d{3})(?!\d)', 'OLDER')

但这对我想要的效果不太好。我想要这样的输出

 Data        ID     older
0                 The ALI**OLDER for 90 days but not 77731929
1                 For all ALI**1952 28A 177945
2                 But the ALI**OLDER and ALI**OLDER 1912

如何更改我的正则表达式 str.replace(r'(?&lt;!\d)(\d{3})(?!\d)' 来做到这一点?

【问题讨论】:

  • 用你的正则表达式它也会匹配1912,你想要替换的数字总是在*前面吗?
  • 是的,它们前面总是有*
  • 检查this这是您要找的吗?
  • 看起来完全正确

标签: regex python-3.x string pandas replace


【解决方案1】:

你可以用这个

(?<=\*)(?:0\d{3}|1[0-8]\d{2}|19[0-2]\d)(?!\d)
  • (?&lt;=\*) - 前面应该有 *
  • (?:0\d{3}|1[0-8]\d{2}|19[0-2]\d)
    • 0\d{3} - 匹配 0000 to 0999 之间的任何 4 位数字
    • | - 交替
    • 1[0-8]\d{2} - 匹配 1000 to 1899 之间的任何 4 位数字
    • | - 交替
    • 19[0-2]\d - 匹配任何 4 位数字 1900 to 1929
  • (?!\d) - 后面不能跟数字

Regex Demo

【讨论】:

    【解决方案2】:

    str.extractallnp.wherestr.replace 一起使用:

    nums = dataframe['Data'].str.extractall('(?<=\*\*ALI\*\*)(\d+)').astype(int).unstack()
    
    dataframe['older'] = np.where(nums.le(1929).any(axis=1), 
                                  dataframe['Data'].str.replace('(?<=\*\*ALI\*\*)(\d+)', 'OLDER'), 
                                  dataframe['Data'])
    

    输出

                                                Data  ID                                           older
    0  The **ALI**1929 for 90 days but not 77731929    1  The **ALI**OLDER for 90 days but not 77731929 
    1               For all **ALI**1952  28A 177945    2                For all **ALI**1952  28A 177945 
    2       But the **ALI**1914 and **ALI**1903 1912   3      But the **ALI**OLDER and **ALI**OLDER 1912
    

    【讨论】:

    • 这真的很接近。但它错过了1929
    【解决方案3】:
    dataframe.Data.str.replace(r"(?<=\*ALI[*]{2})1[0-9](?:(?:[0-4][0-9])|5[0-1])\b","OLDER")
    Out[364]: 
    0    The **ALI**OLDER for 90 days but not 77731929 
    1                  For all **ALI**1952  28A 177945 
    2        But the **ALI**OLDER and **ALI**OLDER 1912
    Name: Data, dtype: object
    
    • (?&lt;=\*ALI[*]{2}) 前面是`*ALI**
    • 1[0-9]即10-19
    • (?: 外部非捕获组的开始
      • (?:[0-4][0-9]) 即 00-49 但未捕获
      • |5[01]即50-51
    • ) 非捕获组结束
    • \b边界

    【讨论】:

      【解决方案4】:

      定义一个自定义 repl 可调用并将其与 str.replace 一起使用

      repl = lambda m: m.group(1) if int(m.group(1)) > 1929 else 'OLDER'
      df.Data.str.replace(r'(?<=\*\*ALI\*\*)(\d+)', repl)
      
      Out[662]:
      0    The **ALI**OLDER for 90 days but not 77731929
      1                  For all **ALI**1952  28A 177945
      2        But the **ALI**OLDER and **ALI**OLDER 1912
      Name: Data, dtype: object
      

      【讨论】:

        【解决方案5】:

        正如我所见,正则表达式应该匹配 **ALI**nnnnnnnn - 4 位数字)并且:

        • 最初的** - 应该(总是)删除。
        • ALI** - 应该保持不变。
        • nnnn - 可以选择替换为 OLDER

        在这种情况下,不需要复杂的正则表达式。 整个逻辑可以包含在“替换”函数中。

        定义如下:

        def repl(mtch):
            g1, g2 = mtch.group(1), mtch.group(2)
            return g1 + (g2 if int(g2) > 1929 else 'OLDER')
        

        然后在这个函数中使用str.replace

        df.Data = df.Data.str.replace(r'\*\*(ALI\*\*)(\d{4})(?!\d)', repl)
        

        请注意,我还更改了正则表达式,定义了 2 个捕获组。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-11-28
          • 2023-03-06
          • 2020-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-04
          • 1970-01-01
          相关资源
          最近更新 更多