我试图将我系统宏的以下EBNF grammar编码为正则表达式(如下),但尽管我付出了最大的努力,但似乎贪婪地匹配多个宏:不会在收盘时}}@
停止。
Expand ``@{{...}}@`` references which may appear in Step parameters.
The syntax is described by the following EBNF grammar::
depdata = "@{{", source identifier, ":", attribute, "}}@"
| "@{{TAGS:", expression, "}}@" ;
source identifier = ? printable 7-bit ASCII ? ;
attribute = "DATADIR" | "TAGSFILE" | "RESULT_INT" ;
expression = ? printable 7-bit ASCII ? ;
和我提出的Python正则表达式
@{{(?:(?:(?P<id>.*?):(?P<attr>DATADIR|TAGSFILE|RESULT_INT))|TAGS:(?P<expr>.+?))}}@
修改:在+
群组中添加了遗失expr
在以下测试用例中找到所有匹配项时,我希望结果是三个匹配,但我只得到两个:
@{{TAGS:sTagsJob << "job||ID||source"}}@ test @{{job:DATADIR}}@ email body @{{job:DATADIR}}@ blah
我期待的比赛是:
@{{TAGS:sTagsJob << "job||ID||source"}}@
设置了expr
组
{li> @{{job:DATADIR}}@
设置了id
和attr
组
@{{job:DATADIR}}@
(再次)设置了id
和attr
组但相反,匹配是:
@{{TAGS:sTagsJob << "job||ID||source"}}@ test @{{job:DATADIR}}@
@{{job:DATADIR}}@
为什么非贪婪的比赛(.+?
)似乎贪得无厌?我错过了什么?
(是的,我知道EBNF语法是愚蠢的,并且可以通过始终将固定字符串显示在右侧来改进。但这不是我的问题:我想知道为什么我的正则表达式失败了我)
答案 0 :(得分:3)
点匹配任何字符(如果 DOTALL 模式关闭,则为换行符)。 *
和*?
匹配0+字符,只有.*
一次抓取所有内容,*?
一步一步地执行,在重试之前检查后续子模式是否匹配*?
subppatern。?
。你在这里混淆了“贪婪”的含义:请注意,正则表达式试图“通过各种方式”找到匹配,当字符串中的某个位置发生不匹配时,它重试量化的子模式,引擎使用贪婪的量词回溯,它确实一切来获取匹配。延迟量词并不能保证您的模式不会因为量词定义中的额外@{{(?P<id>TAGS|[ -~]+?):(?:(?P<attr>DATADIR|TAGSFILE|RESULT_INT)|(?P<expr>[ -~]+?))}}@
而过度激活。
因此,如果您不是真的意味着,如果模式已知,则避免使用点匹配模式。在这里,需要可打印的ASCII模式 - 然后使用它,不依赖于点匹配。
[ -~]
请参阅regex demo
请注意@{{
匹配任何可打印的ASCII字符。请参阅My favorite regex of all time。
模式匹配:
(?P<id>TAGS|[ -~]+?)
- 前导分隔符id
- TAGS
组匹配:
或1个可打印的ASCII字符,但尽可能少,因为它也匹配:
(您可以限制字符类预先排除[ -9;-~]
或替换?
以使模式更加优化并使用此量词摆脱:
:
- 文字(?:(?P<attr>DATADIR|TAGSFILE|RESULT_INT)|(?P<expr>[ -~]+?))
DATADIR
- 匹配TAGSFILE
,RESULT_INT
或attr
并放入[ -~]
组,或匹配一个或多个可打印的ASCII(尽可能少) )并放入组“expr”。同样,这里很懒,因为}
与(?:(?!}}@)[ -~])+
匹配。否则,您可以在}}@
使用tempered greedy token:---
grails:
profile: web
codegen:
defaultPackage: grailsapp
info:
app:
name: '@info.app.name@'
version: '@info.app.version@'
grailsVersion: '@info.app.grailsVersion@'
spring:
groovy:
template:
check-template-location: false
---
grails:
mime:
disable:
accept:
header:
userAgents:
- Gecko
- WebKit
- Presto
- Trident
types:
all: '*/*'
atom: application/atom+xml
css: text/css
csv: text/csv
form: application/x-www-form-urlencoded
html:
- text/html
- application/xhtml+xml
js: text/javascript
json:
- application/json
- text/json
multipartForm: multipart/form-data
pdf: application/pdf
rss: application/rss+xml
text: text/plain
hal:
- application/hal+json
- application/hal+xml
xml:
- text/xml
- application/xml
urlmapping:
cache:
maxsize: 1000
controllers:
defaultScope: singleton
converters:
encoding: UTF-8
views:
default:
codec: html
gsp:
encoding: UTF-8
htmlcodec: xml
codecs:
expression: html
scriptlets: html
taglib: none
staticparts: none
---
hibernate:
cache:
queries: false
use_second_level_cache: true
use_query_cache: false
region.factory_class: 'org.hibernate.cache.ehcache.EhCacheRegionFactory'
endpoints:
jmx:
unique-names: true
dataSource:
pooled: true
jmxExport: true
driverClassName: com.mysql.jdbc.Driver
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
username: root
password: root
environments:
development:
dataSource:
dbCreate: update
url: jdbc:mysql://localhost/inventory
test:
dataSource:
driverClassName: org.h2.Driver
username: sa
password:
dbCreate: update
url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
production:
dataSource:
dbCreate: update
url: jdbc:h2:./prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
properties:
jmxEnabled: true
initialSize: 5
maxActive: 50
minIdle: 5
maxIdle: 25
maxWait: 10000
maxAge: 600000
timeBetweenEvictionRunsMillis: 5000
minEvictableIdleTimeMillis: 60000
validationQuery: SELECT 1
validationQueryTimeout: 3
validationInterval: 15000
testOnBorrow: true
testWhileIdle: true
testOnReturn: false
jdbcInterceptors: ConnectionState
defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED
。请参阅demo public class StudentsGroup implements IFile, Comparable<StudentsGroup> {
private List<Student> studentsList = new ArrayList<Student>();
public int compareTo(StudentsGroup sg) {
return Integer.compare(getTotalPoints(), sg.getTotalPoints());
}
public int getTotalPoints() {
return Math.toIntExact(studentsList.stream()
.mapToInt(Student::getStudentPoints).sum());
}
}
- 尾随分隔符答案 1 :(得分:0)
这是一个似乎做你想做的正则表达式:
@{{(?:(?:(?P<id>[^:]*?):(?P<attr>DATADIR|TAGSFILE|RESULT_INT))|TAGS:(?P<expr>.*?))}}@
MATCH 1
expr [8-37] `sTagsJob << "job||ID||source"`
MATCH 2
id [50-53] `job`
attr [54-61] `DATADIR`
MATCH 3
id [79-82] `job`
attr [83-90] `DATADIR`
你的正则表达式中有一个错误阻止它匹配TAG
部分(忘记P<expr>.?))}}@
中的kleene星?),但仅凭这一点并不能解决匹配过多的问题,所以我在<id>
之后将点更改为“非冒号”。