REGEX:删除带有一个或两个字母的字符串之间的空格
REGEX: Remove spaces between strings with one or two letters
考虑以下 table 第一列中显示的原始字符串:
Original String Parsed String Desired String
'W. & J. JOHNSON LMT.COM' #W J JOHNSON LIMITED #WJ JOHNSON LIMITED
'NORTH ROOF & WORKS CO. LTD.' #NORTH ROOF WORKS CO LTD #NORTH ROOF WORKS CO LTD
'DAVID DOE & CO., LIMITED' #DAVID DOE CO LIMITED #DAVID DOE CO LIMITED
'GEORGE TV & APPLIANCE LTD.' #GEORGE TV APPLIANCE LTD #GEORGE TV APPLIANCE LTD
'LOVE BROS. & OTHERS LTD.' #LOVE BROS OTHERS LTD #LOVE BROS OTHERS LTD
'A. B. & MICHAEL CLEAN CO. LTD.'#A B MICHAEL CLEAN CO LTD #AB MICHAEL CLEAN CO LTD
'C.M. & B.B. CLEANER INC.' #C M B B CLEANER INC #CMBB CLEANER INC
需要删除标点符号,我已按如下方式删除:
def transform(word):
word = re.sub(r'(?<=[A-Za-z])\'(?=[A-Za-z])[A-Z]|[^\w\s]|(.com|COM)',' ',word)
不过,还有最后一点我没能搞定。删除标点符号后,我得到了很多空格。我怎样才能拥有一个将首字母组合在一起并为常规单词保留单个空格(无首字母)的正则表达式?
这种替换上述字符以获得所需字符串的方法不好吗?
感谢您让我继续学习:)
仅在正则表达式中执行此操作不会很好,也不是最佳解决方案,但是,就是这样!您最好采用多步骤方法。我所做的是确定所有可能的情况,并选择找到没有替换字符串的解决方案,因为您并不总是用 spaces.
替换字符
规则
- 非"Stacked"缩写
- 这些位置类似于
A. B.
或 W. & J.
,但不是 C.M. & B.B.
- 我已经将这些识别为前后存在缩写部分(例如
A.
)的位置,但后者后面没有跟另一个字母字符
- 之前 Space
- 这些位置在您的文本中不存在,但如果 space 位于非字母字符之前且后面没有 space(比如在行尾)
- 在这些情况下,我们匹配第一个 space 之后的字符
- 进行中Space
- 这些位置类似于
&
和 J.
中的点
- 我们匹配那些例子中最后一个space之前的字符
- 没有Spaces
- 这些位置类似于
'LOVE
(该字符串中的撇号)
- 我们只匹配非字母非白色space 个字符
正则表达式
实现此目的的一体式正则表达式如下:
(?<=\b[a-z])[^a-z]+(?=[a-z]\b(?![^a-z][a-z]))|(?<= ) *(?:\.com\b|[^a-z\s]+) *| *(?:\.com\b|[^a-z\s]+) *(?= )|(?<! )(?:\.com\b|[^a-z\s]+)(?! )
工作方式如下(分为每个交替):
(?<=\b[a-z])[^a-z]+(?=[a-z]\b(?![^a-z][a-z]))
匹配 A.
和 B.
之间的非字母字符,但不匹配 A.
和 B.B
之间的非字母字符
(?<=\b[a-z])
正后视确保前面是字母字符并断言其左侧的单词边界位置
[^a-z]+
匹配任何非字母字符一次或多次
(?=[a-z]\b(?![^a-z][a-z]))
确保以下内容存在的正面前瞻
[a-z]\b
匹配任何字母字符并断言其右侧的单词边界位置
(?![^a-z][a-z])
负先行确保后面的不是非字母字符后跟字母字符
(?<= ) *(?:\.com\b|[^a-z\s]+) *
确保前面有一个 space,然后匹配任何 space、.com
或任何非单词非白色 space 字符或更多次,然后是任何 spaces
(?<= )
积极回顾确保 space 先于
*
匹配任意数量的 spaces
(?:\.com\b|[^a-z\s]+)
匹配 .com
并确保后跟一个非单词字符,或者匹配任何非单词非白色space 字符一次或多次
*
匹配任意数量的 spaces
*(?:\.com\b|[^a-z\s]+) *(?= )
匹配任何 space、.com
或任何非单词非白色 space 字符一次或多次,然后匹配任何 spaces,然后确保 space 跟随
- 与之前相同,但不是开始时的积极回顾,而是结束时的积极回顾
(?<! )(?:\.com\b|[^a-z\s]+)(?! )
匹配 .com
或任何非字母非白色 space 字符一次或多次,确保没有 space 包围它
- 与前两个选项相同,但使用负向后看和负向前视
代码
import re
strings = [
"'W. & J. JOHNSON LMT.COM'",
"'NORTH ROOF & WORKS CO. LTD.'",
"'DAVID DOE & CO., LIMITED'",
"'GEORGE TV & APPLIANCE LTD.'",
"'LOVE BROS. & OTHERS LTD.'",
"'A. B. & MICHAEL CLEAN CO. LTD.'",
"'C.M. & B.B. CLEANER INC.'"
]
r = re.compile(r'(?<=\b[a-z])[^a-z]+(?=[a-z]\b(?![^a-z][a-z]))|(?<= ) *(?:\.com\b|[^a-z\s]+) *| *(?:\.com\b|[^a-z\s]+) *(?= )|(?<! )(?:\.com\b|[^a-z\s]+)(?! )', re.IGNORECASE)
def transform(word):
return re.sub(r, '', word)
for s in strings:
print(transform(s))
输出:
WJ JOHNSON LMT
NORTH ROOF WORKS CO LTD
DAVID DOE CO LIMITED
GEORGE TV APPLIANCE LTD
LOVE BROS OTHERS LTD
AB MICHAEL CLEAN CO LTD
CM BB CLEANER INC
编辑
使用回调,您可以扩展此逻辑以包括特殊情况,如我的回答下方的评论中所述,以匹配特定情况并进行有条件的替换。
这些特殊情况包括:
FONTAINE'S
到 FONTAINE
PREMIUM-FIT AUTO
到 PREMIUM FIT AUTO
62325 W.C.
到 62325 WC
我在正则表达式中添加了一个新的交替:(\b[\'-]\b(?:[a-z\d] )?)
以捕获字母之间的 'S
或 -
(还有 -S
或类似的)并将其替换为 space 使用回调(如果捕获组存在)。
我仍然建议使用多个正则表达式来完成此操作,但我想证明使用单个模式也是可能的。
import re
strings = [
"'W. & J. JOHNSON LMT.COM'",
"'NORTH ROOF & WORKS CO. LTD.'",
"'DAVID DOE & CO., LIMITED'",
"'GEORGE TV & APPLIANCE LTD.'",
"'LOVE BROS. & OTHERS LTD.'",
"'A. B. & MICHAEL CLEAN CO. LTD.'",
"'C.M. & B.B. CLEANER INC.'",
"'FONTAINE'S PREMIUM-FIT AUTO 62325 W.C.'"
]
r = re.compile(r'(?<=\b[a-z\d])[^a-z\d]+(?=[a-z\d]\b(?![^a-z\d][a-z\d]))|(?<= ) *(?:\.com\b|[^a-z\d\s]+) *| *(?:\.com\b|[^a-z\d\s]+) *(?= )|(\b[\'-]\b(?:[a-z\d] )?)|(?<! )(?:\.com\b|[^a-z\d\s]+)(?! )', re.IGNORECASE)
def repl(m):
return ' ' if m.group(1) else ''
for s in strings:
print(r.sub(repl, s))
我认为分部分进行比较简单。首先,删除 .com
和 space
或 &
以外的任何标点符号。然后,删除仅由一个字母包围的 space
或 &
。最后,将任何剩余的 space
或 &
序列替换为单个 space:
import re
strings = ['W. & J. JOHNSON LMT.COM',
'NORTH ROOF & WORKS CO. LTD.',
'DAVID DOE & CO., LIMITED',
'GEORGE TV & APPLIANCE LTD.',
'LOVE BROS. & OTHERS LTD.',
'A. B. & MICHAEL CLEAN CO. LTD.',
'C.M. & B.B. CLEANER INC.'
]
for s in strings:
s = re.sub(r'\.COM|[^a-zA-Z& ]+', '', s, 0, re.IGNORECASE)
s = re.sub(r'(?<=\b\w)\s*[ &]\s*(?=\w\b)', '', s)
s = re.sub(r'\s*[& ]\s*', ' ', s)
print s
输出
WJ JOHNSON LMT
NORTH ROOF WORKS CO LTD
DAVID DOE CO LIMITED
GEORGE TV APPLIANCE LTD
LOVE BROS OTHERS LTD
AB MICHAEL CLEAN CO LTD
CM BB CLEANER INC
更新
这是在编辑更改最后数据所需结果的问题之前写的。鉴于编辑,上面的代码可以简化为
for s in strings:
s = re.sub(r'\.COM|[^a-zA-Z ]+|\s(?=&)|(?<!\w\w)\s+(?!\w\w)', '', s, 0, re.IGNORECASE)
print s
这是我可以用一个正则表达式模式得到的最简单的:
\.COM|(?<![A-Z]{2}) (?![A-Z]{2})|[.&,]| (?>)&
基本上,它会删除符合 3 个条件的字符:
- 文字“.COM”
- 前后没有 2 个大写字母的空格
- 点、& 符号和逗号,无论它们出现在哪里
- 空格后跟符号
考虑以下 table 第一列中显示的原始字符串:
Original String Parsed String Desired String
'W. & J. JOHNSON LMT.COM' #W J JOHNSON LIMITED #WJ JOHNSON LIMITED
'NORTH ROOF & WORKS CO. LTD.' #NORTH ROOF WORKS CO LTD #NORTH ROOF WORKS CO LTD
'DAVID DOE & CO., LIMITED' #DAVID DOE CO LIMITED #DAVID DOE CO LIMITED
'GEORGE TV & APPLIANCE LTD.' #GEORGE TV APPLIANCE LTD #GEORGE TV APPLIANCE LTD
'LOVE BROS. & OTHERS LTD.' #LOVE BROS OTHERS LTD #LOVE BROS OTHERS LTD
'A. B. & MICHAEL CLEAN CO. LTD.'#A B MICHAEL CLEAN CO LTD #AB MICHAEL CLEAN CO LTD
'C.M. & B.B. CLEANER INC.' #C M B B CLEANER INC #CMBB CLEANER INC
需要删除标点符号,我已按如下方式删除:
def transform(word):
word = re.sub(r'(?<=[A-Za-z])\'(?=[A-Za-z])[A-Z]|[^\w\s]|(.com|COM)',' ',word)
不过,还有最后一点我没能搞定。删除标点符号后,我得到了很多空格。我怎样才能拥有一个将首字母组合在一起并为常规单词保留单个空格(无首字母)的正则表达式?
这种替换上述字符以获得所需字符串的方法不好吗?
感谢您让我继续学习:)
仅在正则表达式中执行此操作不会很好,也不是最佳解决方案,但是,就是这样!您最好采用多步骤方法。我所做的是确定所有可能的情况,并选择找到没有替换字符串的解决方案,因为您并不总是用 spaces.
替换字符规则
- 非"Stacked"缩写
- 这些位置类似于
A. B.
或W. & J.
,但不是C.M. & B.B.
- 我已经将这些识别为前后存在缩写部分(例如
A.
)的位置,但后者后面没有跟另一个字母字符
- 这些位置类似于
- 之前 Space
- 这些位置在您的文本中不存在,但如果 space 位于非字母字符之前且后面没有 space(比如在行尾)
- 在这些情况下,我们匹配第一个 space 之后的字符
- 进行中Space
- 这些位置类似于
&
和J.
中的点
- 我们匹配那些例子中最后一个space之前的字符
- 这些位置类似于
- 没有Spaces
- 这些位置类似于
'LOVE
(该字符串中的撇号) - 我们只匹配非字母非白色space 个字符
- 这些位置类似于
正则表达式
实现此目的的一体式正则表达式如下:
(?<=\b[a-z])[^a-z]+(?=[a-z]\b(?![^a-z][a-z]))|(?<= ) *(?:\.com\b|[^a-z\s]+) *| *(?:\.com\b|[^a-z\s]+) *(?= )|(?<! )(?:\.com\b|[^a-z\s]+)(?! )
工作方式如下(分为每个交替):
(?<=\b[a-z])[^a-z]+(?=[a-z]\b(?![^a-z][a-z]))
匹配A.
和B.
之间的非字母字符,但不匹配A.
和B.B
之间的非字母字符(?<=\b[a-z])
正后视确保前面是字母字符并断言其左侧的单词边界位置[^a-z]+
匹配任何非字母字符一次或多次(?=[a-z]\b(?![^a-z][a-z]))
确保以下内容存在的正面前瞻[a-z]\b
匹配任何字母字符并断言其右侧的单词边界位置(?![^a-z][a-z])
负先行确保后面的不是非字母字符后跟字母字符
(?<= ) *(?:\.com\b|[^a-z\s]+) *
确保前面有一个 space,然后匹配任何 space、.com
或任何非单词非白色 space 字符或更多次,然后是任何 spaces(?<= )
积极回顾确保 space 先于*
匹配任意数量的 spaces(?:\.com\b|[^a-z\s]+)
匹配.com
并确保后跟一个非单词字符,或者匹配任何非单词非白色space 字符一次或多次*
匹配任意数量的 spaces
*(?:\.com\b|[^a-z\s]+) *(?= )
匹配任何 space、.com
或任何非单词非白色 space 字符一次或多次,然后匹配任何 spaces,然后确保 space 跟随- 与之前相同,但不是开始时的积极回顾,而是结束时的积极回顾
(?<! )(?:\.com\b|[^a-z\s]+)(?! )
匹配.com
或任何非字母非白色 space 字符一次或多次,确保没有 space 包围它- 与前两个选项相同,但使用负向后看和负向前视
代码
import re
strings = [
"'W. & J. JOHNSON LMT.COM'",
"'NORTH ROOF & WORKS CO. LTD.'",
"'DAVID DOE & CO., LIMITED'",
"'GEORGE TV & APPLIANCE LTD.'",
"'LOVE BROS. & OTHERS LTD.'",
"'A. B. & MICHAEL CLEAN CO. LTD.'",
"'C.M. & B.B. CLEANER INC.'"
]
r = re.compile(r'(?<=\b[a-z])[^a-z]+(?=[a-z]\b(?![^a-z][a-z]))|(?<= ) *(?:\.com\b|[^a-z\s]+) *| *(?:\.com\b|[^a-z\s]+) *(?= )|(?<! )(?:\.com\b|[^a-z\s]+)(?! )', re.IGNORECASE)
def transform(word):
return re.sub(r, '', word)
for s in strings:
print(transform(s))
输出:
WJ JOHNSON LMT
NORTH ROOF WORKS CO LTD
DAVID DOE CO LIMITED
GEORGE TV APPLIANCE LTD
LOVE BROS OTHERS LTD
AB MICHAEL CLEAN CO LTD
CM BB CLEANER INC
编辑
使用回调,您可以扩展此逻辑以包括特殊情况,如我的回答下方的评论中所述,以匹配特定情况并进行有条件的替换。
这些特殊情况包括:
FONTAINE'S
到FONTAINE
PREMIUM-FIT AUTO
到PREMIUM FIT AUTO
62325 W.C.
到62325 WC
我在正则表达式中添加了一个新的交替:(\b[\'-]\b(?:[a-z\d] )?)
以捕获字母之间的 'S
或 -
(还有 -S
或类似的)并将其替换为 space 使用回调(如果捕获组存在)。
我仍然建议使用多个正则表达式来完成此操作,但我想证明使用单个模式也是可能的。
import re
strings = [
"'W. & J. JOHNSON LMT.COM'",
"'NORTH ROOF & WORKS CO. LTD.'",
"'DAVID DOE & CO., LIMITED'",
"'GEORGE TV & APPLIANCE LTD.'",
"'LOVE BROS. & OTHERS LTD.'",
"'A. B. & MICHAEL CLEAN CO. LTD.'",
"'C.M. & B.B. CLEANER INC.'",
"'FONTAINE'S PREMIUM-FIT AUTO 62325 W.C.'"
]
r = re.compile(r'(?<=\b[a-z\d])[^a-z\d]+(?=[a-z\d]\b(?![^a-z\d][a-z\d]))|(?<= ) *(?:\.com\b|[^a-z\d\s]+) *| *(?:\.com\b|[^a-z\d\s]+) *(?= )|(\b[\'-]\b(?:[a-z\d] )?)|(?<! )(?:\.com\b|[^a-z\d\s]+)(?! )', re.IGNORECASE)
def repl(m):
return ' ' if m.group(1) else ''
for s in strings:
print(r.sub(repl, s))
我认为分部分进行比较简单。首先,删除 .com
和 space
或 &
以外的任何标点符号。然后,删除仅由一个字母包围的 space
或 &
。最后,将任何剩余的 space
或 &
序列替换为单个 space:
import re
strings = ['W. & J. JOHNSON LMT.COM',
'NORTH ROOF & WORKS CO. LTD.',
'DAVID DOE & CO., LIMITED',
'GEORGE TV & APPLIANCE LTD.',
'LOVE BROS. & OTHERS LTD.',
'A. B. & MICHAEL CLEAN CO. LTD.',
'C.M. & B.B. CLEANER INC.'
]
for s in strings:
s = re.sub(r'\.COM|[^a-zA-Z& ]+', '', s, 0, re.IGNORECASE)
s = re.sub(r'(?<=\b\w)\s*[ &]\s*(?=\w\b)', '', s)
s = re.sub(r'\s*[& ]\s*', ' ', s)
print s
输出
WJ JOHNSON LMT
NORTH ROOF WORKS CO LTD
DAVID DOE CO LIMITED
GEORGE TV APPLIANCE LTD
LOVE BROS OTHERS LTD
AB MICHAEL CLEAN CO LTD
CM BB CLEANER INC
更新
这是在编辑更改最后数据所需结果的问题之前写的。鉴于编辑,上面的代码可以简化为
for s in strings:
s = re.sub(r'\.COM|[^a-zA-Z ]+|\s(?=&)|(?<!\w\w)\s+(?!\w\w)', '', s, 0, re.IGNORECASE)
print s
这是我可以用一个正则表达式模式得到的最简单的:
\.COM|(?<![A-Z]{2}) (?![A-Z]{2})|[.&,]| (?>)&
基本上,它会删除符合 3 个条件的字符:
- 文字“.COM”
- 前后没有 2 个大写字母的空格
- 点、& 符号和逗号,无论它们出现在哪里
- 空格后跟符号