【问题标题】:match part of text based on another column根据另一列匹配部分文本
【发布时间】:2020-10-28 02:52:42
【问题描述】:

我有这个数据集;

text                                    num

test one 3.5 and 60 test tow            3.5/60
test one 3/4 test tow                     3/4
test one 5.0 test 10 tow                  5.0

如果数字匹配,我需要从文本列中删除数字 所以我这样做了:

df['text']=[re.sub('{}'.format(number), '', the_text) for the_text, number in zip(df['text'], df['num'])]

结果变成这样

text                                    num

test one 3.5 and 60 test tow            3.5/60
test one test tow                         3/4
test one test 10 tow                      5.0

如您所见,除了第一行之外,匹配的数字已被删除,因为它不是完全匹配的。 所以我想使用包含函数匹配或任何类似于匹配部分文本的东西。

我希望第一行会变成

测试一个并测试两个

我已经这样做了,但出现错误:

[re.sub(r"\b{}\b".format(word), "", the_text) for the_text, word in zip(df['text'], word='/'.join([r'{}'.format(words) for words in df['num']]) )]

TypeError: zip() takes no keyword arguments

有什么帮助吗?

【问题讨论】:

  • 如果您说您遇到了错误,请始终发布错误消息。
  • 代替'{}'.format(number),试试r'(?<!\d)(?<!\d\.)(?:{})(?!\.?\d)'.format('|'.join([re.escape(x) for x in number.split('/')]))
  • @WiktorStribiżew 不起作用
  • @JoelFan 谢谢你
  • 你的示例数据框是df = pd.DataFrame({'text': ['test one 3.5 and 60 test tow','test one 3/4 test tow', 'test one 5.0 test tow'], 'num': ['3.5/60', '3/4', '5.0']})吗?

标签: python regex pandas match


【解决方案1】:

这行得通:

import re

txt='''\
text                                    num

test one 3.5 and 60 test tow            3.5/60
test one 3/4 test tow                     3/4
test one 5.0 test tow                     5.0'''

for line in txt.splitlines():
    m=re.search(r'^(.*?[ \t]{2,}(?=\d))([0-9.\/]+)$', line)
    if m:
        a,_,b=m.group(2).partition('/')
        if re.search(fr'\b{m.group(2)}\b', m.group(1)):
            l=len(m.group(1))
            s=re.sub(fr'[ ]?\b{m.group(2)}\b', '', m.group(1))
            line=s+' '*(l-len(s))+m.group(2)
        elif re.search(fr'{a}[^/]+{b}', m.group(1)):
            l=len(m.group(1))
            s=re.sub(fr'[ ]?\b{a}\b','',m.group(1))
            s=re.sub(fr'[ ]?\b{b}\b','',s)
            line=s+' '*(l-len(s))+m.group(2)
                
    print(line)     

打印:

text                                    num

test one and test tow                   3.5/60
test one test tow                         3/4
test one test tow                         5.0

【讨论】:

    【解决方案2】:

    你可以使用

    df['text'] = df.apply(lambda x: re.sub(r'(?<!\d)(?<!\d\.)(?:{}|{})(?!\.?\d)'.format(re.escape(x['num']), '|'.join([re.escape(l) for l in x['num'].split('/')])), '', x['text']), axis=1)
    

    感谢df.applyaxis=1,我们遍历所有行。

    正则表达式是根据num 列中的值动态生成的,并应用于text 列。

    r'(?&lt;!\d)(?&lt;!\d\.)(?:{}|{})(?!\.?\d)'.format(re.escape(x['num']), '|'.join([re.escape(l) for l in x['num'].split('/')])) 创建一个类似的正则表达式

    (?<!\d)(?<!\d\.)(?:3/4|3|4)(?!\.?\d)
    

    分别匹配num 列中的完整值和/ 之间的数字。

    (?&lt;!\d)(?&lt;!\d\.) 是一个后向序列,如果在当前位置的左边有一个数字或一个数字 + 点,则匹配失败,如果有一个数字或一个点 +,(?!\.?\d) 则匹配失败当前位置右侧的数字有效地禁止数字匹配较长的数字。

    【讨论】:

      【解决方案3】:

      创建一个数字列表并添加/

      nums = '|'.join(df['num'].tolist()).replace('/', '|') + '|/'
      nums
      '3.5|60|3|4|5.0|/'
      

      然后str替换

      df['text'].str.replace(nums, '')
      
      0    test one  and  test tow
      1         test one  test tow
      2         test one  test tow
      

      【讨论】:

      • 请注意,. 是一个特殊的正则表达式元字符,5.0 将匹配 5 05+0 等等。你需要逃避它。此外,没有任何界限,您将冒着将3 替换为43 的风险。
      • 我想传递 num 列,以便每一行都匹配 text 列上的同一行
      • @WiktorStribiżew 所以如果文本上有任何其他数字,如果不匹配则不会删除
      猜你喜欢
      • 2021-03-28
      • 1970-01-01
      • 2022-01-16
      • 2022-01-07
      • 2012-01-14
      • 1970-01-01
      • 2021-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多