正则表达式如何按大写字母分割?

4
我想使用正则表达式将类似于'HDMWhoSomeThing'的字符串替换为'HDM Who Some Thing'。因此,我想提取以大写字母开头或仅由大写字母组成的单词。请注意,在字符串'HDMWho'中,最后一个大写字母实际上是单词Who的第一个字母 - 不应包括在单词HDM中。
实现此目标的正确正则表达式是什么?我尝试了许多类似于[A-Z][a-z]+的正则表达式,但都没有成功。 [A-Z][a-z]+只给我'Who Some Thing',当然没有'HDM'
有任何想法吗? 谢谢, Rukki
5个回答

2

尝试使用以下正则表达式进行拆分:

/(?=[A-Z][a-z])/

如果您的正则表达式引擎不支持分割空匹配项,可以尝试使用以下正则表达式在单词之间添加空格:

/([A-Z])(?![A-Z])/

用第一组匹配的内容加上一个空格替换它,即" $1"。然后你就可以在空格处分割了。

我正在使用Python。不幸的是,模式(?=[A-Z][a-z])没有匹配到任何内容,而模式([A-Z])(?![A-Z])则返回"W S T" :( - Rukki Odds
@Rukki Odds:我写了,你需要用一个空格替换([A-Z])(?![A-Z])的匹配结果来分隔单词。然后你可以使用\s+来分割这些单词。 - Gumbo
([A-Z])(?![A-Z]) 如果字符串中间有一个全大写单词,这个正则表达式将无法起作用:例如在'HDMWhoSomeMONKEYThing'中只会匹配'Who'、'Some'和'Thing'中的 W、S 和 T。 - Johrn

2
#! /usr/bin/env python

import re
from collections import deque

pattern = r'([A-Z]{2,}(?=[A-Z]|$)|[A-Z](?=[a-z]|$))'
chunks = deque(re.split(pattern, 'HDMWhoSomeMONKEYThingXYZ'))

result = []
while len(chunks):
  buf = chunks.popleft()
  if len(buf) == 0:
    continue
  if re.match(r'^[A-Z]$', buf) and len(chunks):
    buf += chunks.popleft()
  result.append(buf)

print ' '.join(result)

输出:

HDM 谁一些 MONKEY 事情 XYZ

从代码行数来看,这个任务更适合使用re.findall

pattern = r'([A-Z]{2,}(?=[A-Z]|$)|[A-Z][a-z]*)'
print ' '.join(re.findall(pattern, 'HDMWhoSomeMONKEYThingX'))

输出:

HDM 谁某些猴子的东西 X

我认为这个程序在字符串中间包含全大写单词时也会遇到问题。对字符串'HDMWhoSomeMONKEYThing'调用re.split将返回[HDM, Who, SomeMONKEY, Thing]。 - Johrn

2

一句话概括:

使用正则表达式将字符串转化为驼峰命名法。

使用正则表达式:

([A-Z][a-z]+)|(?:([A-Z]*)(?=[A-Z]))

' '.join(a or b for a,b in re.findall('([A-Z][a-z]+)|(?:([A-Z]*)(?=[A-Z]))',s))


这不会匹配字符串末尾的一个大写字母单词。对于插入它们之间的空格的应用程序来说无关紧要,但如果需要对所有单词执行其他操作,则可能会出现问题。 - Johrn

1

可能是 '[A-Z]*?[A-Z][a-z]+' 吗?

编辑:这似乎可以工作:[A-Z]{2,}(?![a-z])|[A-Z][a-z]+

import re

def find_stuff(str):
  p = re.compile(r'[A-Z]{2,}(?![a-z])|[A-Z][a-z]+')
  m = p.findall(str)
  result = ''
  for x in m:
    result += x + ' '
  print result

find_stuff('HDMWhoSomeThing')
find_stuff('SomeHDMWhoThing')

输出:

HDM 谁某事

某 HDM 谁事物


几乎正确 - 但它给出的是"HDMWho Some Thing"而不是"HDM Who Some Thing"。 - Rukki Odds
我的精确代码: str = 'HDMWhoSomeThing'\n p = re.compile('[A-Z]*?[A-Z][a-z]+')\n m = p.findall('HDMWhoSomeThing')\n result = ''\n for x in m:\n result += x + ' '\n print result\n我已将行尾改为 \n。 - Rukki Odds
字符串中缺少一个大写字母单词:'HDMWhoSomeAThingA' 不会匹配 'A'(将 {2,} 改为 + 就可以抓取一个字符的单词) - Johrn

1

因此,在这种情况下,“单词”是:

  1. 任意数量的大写字母 - 除非最后一个大写字母后面跟着一个小写字母。
  2. 一个大写字母后面跟着任意数量的小写字母。

所以尝试:

([A-Z]+(?![a-z])|[A-Z][a-z]*)

第一个选择包括否定前瞻 (?![a-z]),它处理全大写单词和首字母大写单词之间的边界。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接