【问题标题】:Applying regex to pandas column based on different pos of same character根据相同字符的不同位置将正则表达式应用于熊猫列
【发布时间】:2025-12-03 19:50:02
【问题描述】:

我有一个如下所示的数据框

tdf = pd.DataFrame({'text_1':['value: 1.25MG - OM - PO/TUBE - ashaf', 'value:2.5 MG - OM - PO/TUBE -test','value: 18 UNITS(S)','value: 850 MG - TDS AFTER FOOD - SC (SUBCUTANEOUS) -had', 'value: 75 MG - OM - PO/TUBE']})

我想应用正则表达式并根据下面给出的规则创建两列

col val 应该存储value: 之后和first hyphen 之前的所有文本

col Adm 应该存储third hyphen 之后的所有文本

我尝试了以下方法,但它不能正常工作

tdf['text_1'].str.findall('[.0-9]+\s*[mgMG/lLcCUNIT]+')

【问题讨论】:

    标签: python regex pandas string dataframe


    【解决方案1】:

    对于您显示的示例,您能否尝试以下操作。

    tdf[["val", "Adm"]] = tdf["text_1"].str.extract(r'^value:\s?(\S+(?:\s[^-]+)?)(?:\s-\s.*?-([^-]*)(?:-.*)?)?$', expand=True)
    tdf
    

    Online demo for above regex

    输出如下。

                                                        text_1          val                  Adm
    0                     value: 1.25MG - OM - PO/TUBE - ashaf       1.25MG             PO/TUBE 
    1                        value:2.5 MG - OM - PO/TUBE -test       2.5 MG             PO/TUBE 
    2                                       value: 18 UNITS(S)  18 UNITS(S)                  NaN
    3  value: 850 MG - TDS AFTER FOOD - SC (SUBCUTANEOUS) -had       850 MG   SC (SUBCUTANEOUS) 
    4                              value: 75 MG - OM - PO/TUBE        75 MG              PO/TUBE
    

    说明:为上述添加详细说明。

    ^value:\s?       ##Checking if value starts from value: space is optional here.
    (\S+             ##Starting 1st capturing group from here and matching all non space here.
      (?:\s[^-]+)?   ##In a non-capturing group matching space till - comes keeping it optional.
    )                ##Closing 1st capturing group here.
    (?:\s-\s.*?-     ##In a non-capturing group matching space-space till - first occurrence.
      ([^-]*)        ##Creating 2nd capturing group which has values till next - here.
      (?:-.*)?       ##In a non capturing group from - till end of value keeping it optional.
    )?$              ##Closing non-capturing group at the end of the value here.
    

    【讨论】:

    • @TheGreat,请告诉我它不适用于哪些样本。您展示的样品对我来说效果很好。
    • 哦,抱歉,我以为您阅读了我对上一个答案的评论。我现在更新了我的示例数据框。
    • 抱歉,奖励解决方案不适用于更新后的示例
    【解决方案2】:

    Series.str.extract

    tdf['text_1'].str.extract(r'^value:\s?([^-]+)(?:\s-.*?-\s)?([^-]*)(?:\s|$)')
    

                 0                  1
    0       1.25MG            PO/TUBE
    1       2.5 MG            PO/TUBE
    2  18 UNITS(S)                   
    3       850 MG  SC (SUBCUTANEOUS)
    4        75 MG            PO/TUBE
    

    正则表达式详细信息:

    • ^ : 在行首断言位置
    • value::匹配字符序列value:
    • \s?:匹配零到一次之间的任何空白字符
    • ([^-]+) :第一个捕获组匹配除- 之外的任何字符一次或多次
    • (?:\s-.*?-\s)? : 零和一次之间的非捕获组匹配
      • \s: 匹配单个空白字符
      • - :匹配字符 -
      • .*? :匹配零次到无限次之间的任何字符,但尽可能少地匹配
      • - :匹配字符 -
      • \s : 匹配单个空白字符
    • ([^-]*) :第二个捕获组匹配除- 之外的任何字符零次或多次
    • (?:\s|$) :非捕获组
      • \s- : 匹配单个空白字符
      • |:或者切换
      • $ : 在行尾断言位置

    See the online Regex demo

    【讨论】:

      【解决方案3】:

      你可以使用

      tdf[["val", "Adm"]] = tdf["text_1"].str.extract(r'^val:\s*([^-]*?)(?:\s*-[^-]*-\s*(.*))?$', expand=True)
      # => >>> tdf
                                                   text_1          val  \
      0                        val: 1.25MG - OM - PO/TUBE       1.25MG   
      1                         val:2.5 MG - OM - PO/TUBE       2.5 MG   
      2                                  val: 18 UNITS(S)  18 UNITS(S)   
      3  val: 850 MG - TDS AFTER FOOD - SC (SUBCUTANEOUS)       850 MG   
      4                         val: 75 MG - OM - PO/TUBE        75 MG   
      
      
      0            PO/TUBE  
      1            PO/TUBE  
      2                NaN  
      3  SC (SUBCUTANEOUS)  
      4            PO/TUBE  
      

      请参阅regex demo

      详情

      • ^val: - val: 在字符串的开头(如果 val: 并不总是在字符串的开头,请删除 ^ 锚点)
      • \s* - 零个或多个空格
      • ([^-]*?) - 第 1 组:- 以外的任何字符尽可能少
      • (?:\s*-[^-]*-\s*(.*))? - 可选序列
        • \s* - 零个或多个空格
        • -[^-]*- - 一个-,除- 之外的任何零个或多个字符,然后是-
        • \s* - 零个或多个空格
        • (.*) - 第 2 组:线路的其余部分
      • $ - 字符串结束。

      【讨论】:

      • 一个小问题。假设我想对列重新排序。意思是,Adm 应该排在第一位,val 应该排在最后一列。正则表达式会保持不变吗?
      • 抱歉,我不在办公桌前,无法尝试
      • @TheGreat 解压后可以reorder the columns,添加tdf = tdf[['text_1', 'Adm', 'val']]这一行。
      • 谢谢,最后一个问题。我正在尝试更改您的正则表达式以选择3rd hyphen 之后但4th hyphen 之前的所有文本......所以,我写了下面的tdf["text_1"].str.extract(r'^value:\s*([^-]*?)(?:\s*-[^-]*-\s*(.*))?[^-]*', expand=True) 但这似乎给出了不正确的输出。你能帮忙吗?
      • @TheGreat 那将是^val:\s*([^-]*?)(?:\s*-[^-]*-\s*([^-]*)),请参阅demo
      最近更新 更多