Python 使用 re 在字符之间创建空格,方括号中的字符除外

Python using re to create spaces between characters except for those in square brackets

我有一个数据框:

d1  ={'letters':['ABCDE[NOT]FGH', 'CCGF[NOT]HI', 'MPJ[NOT]L', 'MNA[NOT]PLJKAJSHD']}
df1 = pd.DataFrame(d1)

df1:

letters
0   ABCDE[NOT]FGH
1   CCGF[NOT]HI
2   MPJ[NOT]L
3   MNA[NOT]PLJKAJSHD

我想在除 [ ] 之间的字符之外的每个字符之间创建一个 space。

期望的输出:

letters
0   A B C D E [NOT] F G H
1   C C G F [NOT] H I
2   M P J [NOT] L
3   M N A [NOT] P L J K A J S H D

我试过:

matching = re.sub(r'[^a-zA-Z []]+(?![^{]*})(\w)', r'', i)

df1['letters'].apply(lambda x: matching)

但这似乎不起作用。 有什么想法吗?

您可以将 space 附加到每个 [...] 子字符串或在字符串中找到的任何其他字符,然后 rstrip 结果:

>>> df1['letters'].str.replace(r'\[[^][]*]|.', r'\g<0> ', regex=True).str.rstrip()
0            A B C D E [NOT] F G H
1                C C G F [NOT] H I
2                    M P J [NOT] L
3    M N A [NOT] P L J K A J S H D
Name: letters, dtype: object

参见 this regex demo

另一种方法是在与 \[[^][]*] 模式匹配的字符以外的任何字符周围添加 spaces,然后 str.strip() 结果:

>>> df1['letters'].str.replace(r'(\[[^][]*])|.', lambda x: x.group(1) if x.group(1) else f" {x.group()} ", regex=True).str.strip()
0                A  B  C  D  E [NOT] F  G  H
1                      C  C  G  F [NOT] H  I
2                            M  P  J [NOT] L
3    M  N  A [NOT] P  L  J  K  A  J  S  H  D
Name: letters, dtype: object

(\[[^][]*])|. 正则表达式匹配并捕获到第 1 组 a [,然后是 [] 以外的任何零个或多个字符,然后是 ] 字符,或除换行符字符以外的任何字符,如果被捕获则替换为第 1 组值,否则替换为“space”+ 匹配值 +“space”。

str.strip() 删除 leading/trailing spaces,如果替换操作产生的话。

非Pandas代码

import re
# Solution 1
text = re.sub(r'\[[^][]*]|.', r'\g<0> ', text).rstrip()

# Solution 1
text = re.sub(r'(\[[^][]*])|.', lambda x: x.group(1) if x.group(1) else f" {x.group()} ", text).strip()

尽管效率极低,但您可以使用它并避免 post-processing:

(?=(?!^)[^\[\]]*?\[|[^\[\]]+$)
  • (?= - 开始前瞻
    • (?!^) - 不要断言字符串的开头
    • [^\[\]]*?\[ - 断言导致左括号 [
    • 的任何位置
    • | - 或
    • [^\[\]]+$ - 断言任何不是通向行尾的括号的位置
  • ) - 关闭前瞻

https://regex101.com/r/zoHEne/1/

注意: regex101 示例仅由于多行而具有尾随空格。一次测试每一行以查看没有尾随空格。

您可以使用 re.findall:

import pandas as pd, re
d1 = {'letters':['ABCDE[NOT]FGH', 'CCGF[NOT]HI', 'MPJ[NOT]L', 'MNA[NOT]PLJKAJSHD']}
df1 = pd.DataFrame(d1)
df1['letters'] = df1['letters'].apply(lambda x:' '.join(re.findall('\[\w+\]|\w', x)))
                         letters
0          A B C D E [NOT] F G H
1              C C G F [NOT] H I
2                  M P J [NOT] L
3  M N A [NOT] P L J K A J S H D