[英]Regular expression to match strings in quotes with double-quotes inside
I face a challenge to match the input in the following format: 我面临着以下列格式匹配输入的挑战:
The regular expression should match the given key=value part of the sequence and should not break for long inputs (eg value is 10000 characters). 正则表达式应该与序列的给定key = value部分匹配,并且不应该为长输入中断(例如,值为10000个字符)。
First I came to this solution: 首先我来到这个解决方案:
/(\w+)=(\d+|"(?:""|[^"])+"(?!"))
and it performs not bad, however it fails in Java6 with StackOverflowError for long inputs (cashes regexplanet for example). 并且它执行得不错,但是在Java6中,对于长输入(例如, cashes regexplanet ),StackOverflowError失败了。 I tried to improve it a bit to run faster:
我尝试改进它以便更快地运行:
/(\w+)=(\d+|"(?:""|[^"]+)+"(?!"))
but then if input is not matching, it enters endless loop in backtracking trying to match it. 但是如果输入不匹配,它会在回溯中进入无限循环,试图匹配它。
Then I came to this regex: 然后我来到这个正则表达式:
/(\w+)=(\d+|".+?(?<!")(?:"")*"(?!"))
which is performing slower, but it seems to solve the task. 表现较慢,但它似乎解决了这个任务。
Can anyone suggest a better / faster regex? 任何人都可以建议更好/更快的正则表达式?
Sample input: 样本输入:
/mol_type="protein" /transl_table=11 /note="[CDS] (""multi
line)" nn /organism="""Some"" Sequence" nn /organism="Some ""Sequence"""
/translation="MHPSSSRIPHIAVVGVSAIFPGSLDAHGFWRDILSGTDLITDVPSTHWLVE
DYYDPDPSAPDKTYAKRGAFLKDVPFDPLEWGVPPSIVPATDTTQLLALIVAKRVLEDAAQGQFE
SMSRERMSVILGVTSAQELLASMVSRIQRPVWAKALRDLGYPEDEVKRACDKIAGNYVPWQESSF
PGLLGNVVAGRIANRLDLGGTNCVTDAACASSLSAMSMAINELALGQSDLVIAGGCDTMNDAFMY
MCFSKTPALSKSGDCRPFSDKADGTLLGEGIAMVALKRLDDAERDGDRVYAVIRGIGSSSDGRSK
SVYAPVPEGQAKALRRTYAAAGYGPETVELMEAHGTGTKAGDAAEFEGLRAMFDESGREDRQWCA
LGSVKSQIGHTKAAAGAAGLFKAIMALHHKVLPPTIKVDKPNPKLDIEKTAFYLNTQARPWIRPG
DHPRRASVSSFGFGGSNFHVALEEYTGPAPKAWRVRALPAELFLLSADTPAALADRARALAKEAE
VPEILRFLARESVLSFDASRPARLGLCATDEADLRKKLEQVAAHLEARPEQALSAPLVHCASGEA
PGRVAFLFPGQGSQYVGMGADALMTFDPARAAWDAAAGVAIADAPLHEVVFPRPVFSDEDRAAQE
ARLRETRWAQPAIGATSLAHLALLAALGVRAEAFAGHSFGEITALHAAGALSAADLLRVARRRGE
LRTLGQVVDHLRASLPAAGPAASASPAAAASVPKASTAAVPAVASVAAPGAAEVERVVMAVVAET
TGYPAEMLGLQMELESDLGIDSIKRVEILSAVRDRTPGLSEVDASALAQLRTLGQVVDHLRASLP
AASAGPAVAAPAAKAPAVAAPTGVSGATPGAAEVERVVMAVVAETTGYPAEMLGLQMELESDLGI
DSIKRVEILSAVRDRTPGLAEVDASALAQLRTLGQVVDHLRASLGPAAVTAGAAPAEPAEEPAST
PLGRWTLVEEPAPAAGLAMPGLFDAGTLVITGHDAIGPALVAALAARGIAAEYAPAVPRGARGAV
FLGGLRELATADAALAVHREAFLAAQAIAAKPALFVTVQDTGGDFGLAGSDRAWVGGLPGLVKTA
ALEWPEASCRAIDLERAGRSDGELAEAIASELLSGGVELEIGLRADGRRTTPRSVRQDAQPGPLP
LGPSDVVVASGGARGVTAATLIALARASHARFALLGRTALEDEPAACRGADGEAALKAALVKAAT
SAGQRVTPAEIGRSVAKILANREVRATLDAIRAAGGEALYVPVDVNDARAVAAALDGVRGALGPV
TAIVHGAGVLADKLVAEKTVEQFERVFSTKVDGLRALLGATAGDPLKAIVLFSSIAARGGNKGQC
DYAMANEVLNKVAAAEAARRPGCRVKSLGWGPWQGGMVNAALEAHFAQLGVPLIPLAAGAKMLLD
ELCDASGDRGARGQGGAPPGAVELVLGAEPKALAAQGHGGRVALAVRADRATHPYLGDHAINGVP
VVPVVIALEWFARAARACRPDLVVTELRDVRVLRGIKLAAYESGGEVFRVDCREVSNGHGAVLAA
ELRGPQGALHYAATIQMQQPEGRVAPKGPAAPELGPWPAGGELYDGRTLFHGRDFQVIRRLDGVS
RDGIAGTVVGLREAGWVAQPWKTDPAALDGGLQLATLWTQHVLGGAALPMSVGALHTFAEGPSDG
PLRAVVRGQIVARDRTKADIAFVDDRGSLVAELRDVQYVLRPDTARGQA"
/note="primer of Streptococcus pneumoniae
Expected output (from regexhero.net ): 预期输出(来自regexhero.net ):
In order to fail in a reasonable time you need, indeed, to avoid catastrophic backtracking. 为了在合理的时间内失败,你确实需要避免灾难性的回溯。 This can be done using atomic grouping
(?>...)
: 这可以使用原子分组
(?>...)
来完成:
/(\w+)=(\d+|"(?>(?>""|[^"]+)+)"(?!"))
# (?>(?>""|[^"]+)+)
(?> # throw away the states created by (...)+
(?> # throw away the states created by [^"]+
""|[^"]+
)+
)
Your issue when using (?:""|[^"]+)+
on a string that will never match, is linked to the fact that each time you match a new [^"]
character the regex engine can choose to use the inner or outer +
quantifier. 在对于永远不会匹配的字符串上使用
(?:""|[^"]+)+
时出现的问题与每次匹配新的[^"]
字符的事实有关,正则表达式引擎可以选择使用内部或外部+
量词。
This leads to a lot of possibilities for backtracking, and before returning a failure the engine has to try them all. 这导致了许多回溯的可能性,并且在返回故障之前,引擎必须尝试所有这些。
We know that if we haven't found a match by the time the engine reaches the end, we never will: all we need to do is throw away the backtracking positions to avoid the issue, and that's what atomic grouping is for. 我们知道,如果我们在引擎到达终点时没有找到匹配,我们永远不会:我们需要做的就是抛弃回溯位置以避免问题,这就是原子分组的用途。
See a DEMO : 24 steps on failure, while preserving the speed on the successful cases (not a real benchmarking tool, but catastrophic backtracking would be pretty easy to spot) 看一个DEMO :失败的24个步骤,同时保留成功案例的速度(不是真正的基准测试工具,但灾难性的回溯很容易发现)
How about this one: 这个怎么样:
/(\w+)=("(?:[^"]|"")*"|\d+)
(Note that the /
is part of the regex here. Escape it as appropriate for your host language.) (请注意,这里是
/
正则表达式的一部分。根据您的宿主语言进行转义。)
If your regex engine supports it (Java does), make the *
possessive : 如果您的正则表达式引擎支持它(Java确实如此),请使
*
占有 :
/(\w+)=("(?:[^"]|"")*+"|\d+)
After some debugging the latter expression can be improved to: 经过一些调试后,后一个表达式可以改进为:
/(\w+)=("(?:""|[^"]*+)*+"|\d++)
Note the double *+)*+
which allows matching contiguous text in one step while not being susceptible to catastrophic backtracking. 请注意double
*+)*+
,它允许在一个步骤中匹配连续文本,同时不易受到灾难性回溯的影响。
Your initial regex was already quite good, but it was more complicated than necessary, leading to catastrophic backtracking . 你的初始正则表达式已经非常好了,但它比必要的更复杂,导致灾难性的回溯 。
You should use 你应该用
/(\w+)=(\d+|"(?:""|[^"])*"(?!"))
See it live on regex101.com . 在regex101.com上直播 。
Explanation: 说明:
/ # Slash
(\w+) # Indentifier --> Group 1
= # Equals sign
( # Group 2:
\d+ # Either a number
| # or
"(?:""|[^"])*" # a quoted string
(?!") # unless another quote follows
) # End of group 2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.