我遵循为在Gemfile中捕获gem名称而定义的正则表达式。
GEM_NAME = /[a-zA-Z0-9\-_\.]+/
QUOTED_GEM_NAME = /(?:(?<gq>["'])(?<name>#{GEM_NAME})\k<gq>|%q<(?<name>#{GEM_NAME})>)/
我想将它们转换为可以在python和其他语言中使用的正则表达式。
我尝试(?:(["'])([a-zA-Z0-9\-_\.]+)\k["']|%q<([a-zA-Z0-9\-_\.]+)>)
基于替换和几个类似的组合,但没有一个工作。这是regexr链接http://regexr.com/3g527
有人可以解释一下将这些ruby正则表达式定义转换为python可以使用的形式的正确过程。
答案 0 :(得分:1)
要定义命名组,您需要使用(?P<name>)
,然后使用(?p=name)
命名
如果你能买得起第三方库,你可以使用PyPi正则表达式模块并使用你在Ruby中使用的方法(因为regex
支持多个同名的捕获组):
s = """%q<Some-name1> "some-name2" 'some-name3'"""
GEM_NAME = r'[a-zA-Z0-9_.-]+'
QUOTED_GEM_NAME = r'(?:(?P<gq>["\'])(?<name>{0})(?P=gq)|%q<(?P<name>{0})>)'.format(GEM_NAME)
print(QUOTED_GEM_NAME)
# => # (?:(?P<gq>["\'])(?<name>[a-zA-Z0-9_.-]+)(?P=gq)|%q<(?P<name>[a-zA-Z0-9_.-]+)>)
import regex
res = [x.group("name") for x in regex.finditer(QUOTED_GEM_NAME, s)]
print(res)
# => ['Some-name1', 'some-name2', 'some-name3']
替换模式中的反向引用。
请参阅this Python demo。
如果您决定使用Python re
,则无法在一个正则表达式模式中处理具有相同名称的组。
您可以完全丢弃已命名的组并使用编号的组,并使用re.finditer
迭代所有匹配并理解以获取正确的捕获。
import re
GEM_NAME = r'[a-zA-Z0-9_.-]+'
QUOTED_GEM_NAME = r"([\"'])({0})\1|%q<({0})>".format(GEM_NAME)
s = """%q<Some-name1> "some-name2" 'some-name3'"""
matches = [x.group(2) if x.group(1) else x.group(3) for x in re.finditer(QUOTED_GEM_NAME, s)]
print(matches)
# => ['Some-name1', 'some-name2', 'some-name3']
因此,([\"'])({0})\1|%q<({0})>
有3个捕获组:如果组1匹配,则第一个替代匹配,因此,组2被采用,否则,第二个替代匹配,并且在理解中抓取组3值
模式详情
([\"'])
- 第1组:"
或'
({0})
- 第2组:GEM_NAME
模式\1
- 对第1组捕获值的内联反向引用(请注意r'...'
原始字符串文字允许使用单个反斜杠在字符串文字中定义反向引用)|
- 或%q<
- 文字子字符串({0})
- 第3组:GEM_NAME
模式>
- 文字>
。答案 1 :(得分:1)
您可以像这样重写您的模式:
GEM_NAME = r'[a-zA-Z0-9_.-]+'
QUOTED_GEM_NAME = r'''["'%] # first possible character
(?:(?<=%)q<)? # if preceded by a % match "q<"
(?P<name> # the three possibilities excluding the delimiters
(?<=") {0} (?=") |
(?<=') {0} (?=') |
(?<=<) {0} (?=>)
)
["'>] #'"# closing delimiter
(?x) # switch the verbose mode on for all the pattern
'''.format(GEM_NAME)
优点:
re.findall
获取宝石列表而无需进一步操作。请注意,您无需转义字符类中的点。
答案 2 :(得分:1)
一种简单的方法是使用条件并合并名称。
(?:(?:(["'])|%q<)(?P<name>[a-zA-Z0-9\-_\.]+)(?(1)\1|>))
扩展
(?:
(?: # Delimiters
( ["'] ) # (1), ' or "
| # or,
%q< # %q
)
(?P<name> [a-zA-Z0-9\-_\.]+ ) # (2), Name
(?(1) \1 | > ) # Did group 1 match ? match it here, else >
)
Python
import re
s = ' "asdf" %q<asdfasdf> '
print ( re.findall( r'(?:(?:(["\'])|%q<)(?P<name>[a-zA-Z0-9\-_\.]+)(?(1)\1|>))', s ) )
输出
[('"', 'asdf'), ('', 'asdfasdf')]