我试图根据双引号之间没有的空格分割一条线。
我的正则表达式是
(([\"]([^\\\"]|\\.)+[\"]|[^ ]+))+
我的代码
Pattern regex = Pattern.compile("(([\"]([^\\\"]|\\.)+[\"]|[^ ]+))+");
Matcher regexMatcher = regex.matcher(line);
List<String> rule = new ArrayList<String>();
while(regexMatcher.find())
rule.add(regexMatcher.group());
失败的输入。
SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "(?i:\b(?:(?:s(?:t(?:d(?:dev(_pop|_samp)?)?|r(?:_to_date|cmp))|u(?:b(?:str(?:ing(_index)?)?|(?:dat|tim)e)|m)|e(?:c(?:_to_time|ond)|ssion_user)|ys(?:tem_user|date)|ha(1|2)?|oundex|chema|ig?n|pace|qrt)|i(?:s(null|_(free_lock|ipv4_compat|ipv4_mapped|ipv4|ipv6|not_null|not|null|used_lock))?|n(?:et6?_(aton|ntoa)|s(?:ert|tr)|terval)?|f(null)?)|u(?:n(?:compress(?:ed_length)?|ix_timestamp|hex)|tc_(date|time|timestamp)|p(?:datexml|per)|uid(_short)?|case|ser)|l(?:o(?:ca(?:l(timestamp)?|te)|g(2|10)?|ad_file|wer)|ast(_day|_insert_id)?|e(?:(?:as|f)t|ngth)|case|trim|pad|n)|t(?:ime(stamp|stampadd|stampdiff|diff|_format|_to_sec)?|o_(base64|days|seconds|n?char)|r(?:uncate|im)|an)|m(?:a(?:ke(?:_set|date)|ster_pos_wait|x)|i(?:(?:crosecon)?d|n(?:ute)?)|o(?:nth(name)?|d)|d5)|r(?:e(?:p(?:lace|eat)|lease_lock|verse)|o(?:w_count|und)|a(?:dians|nd)|ight|trim|pad)|f(?:i(?:eld(_in_set)?|nd_in_set)|rom_(base64|days|unixtime)|o(?:und_rows|rmat)|loor)|a(?:es_(?:de|en)crypt|s(?:cii(str)?|in)|dd(?:dat|tim)e|(?:co|b)s|tan2?|vg)|p(?:o(?:sition|w(er)?)|eriod_(add|diff)|rocedure_analyse|assword|i)|b(?:i(?:t_(?:length|count|x?or|and)|n(_to_num)?)|enchmark)|e(?:x(?:p(?:ort_set)?|tract(value)?)|nc(?:rypt|ode)|lt)|v(?:a(?:r(?:_(?:sam|po)p|iance)|lues)|ersion)|g(?:r(?:oup_conca|eates)t|et_(format|lock))|o(?:(?:ld_passwo)?rd|ct(et_length)?)|we(?:ek(day|ofyear)?|ight_string)|n(?:o(?:t_in|w)|ame_const|ullif)|(rawton?)?hex(toraw)?|qu(?:arter|ote)|(pg_)?sleep|year(week)?|d?count|xmltype|hour)\W*\(|\b(?:(?:s(?:elect\b(?:.{1,100}?\b(?:(?:length|count|top)\b.{1,100}?\bfrom|from\b.{1,100}?\bwhere)|.*?\b(?:d(?:ump\b.*\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_(?:sqlexec|sp_replwritetovarbin|sp_help|addextendedproc|is_srvrolemember|prepare|sp_password|execute(?:sql)?|makewebtask|oacreate)|ql_(?:longvarchar|variant))|xp_(?:reg(?:re(?:movemultistring|ad)|delete(?:value|key)|enum(?:value|key)s|addmultistring|write)|terminate|xp_servicecontrol|xp_ntsec_enumdomains|xp_terminate_process|e(?:xecresultset|numdsn)|availablemedia|loginconfig|cmdshell|filelist|dirtree|makecab|ntsec)|u(?:nion\b.{1,100}?\bselect|tl_(?:file|http))|d(?:b(?:a_users|ms_java)|elete\b\W*?\bfrom)|group\b.*\bby\b.{1,100}?\bhaving|open(?:rowset|owa_util|query)|load\b\W*?\bdata\b.*\binfile|(?:n?varcha|tbcreato)r|autonomous_transaction)\b|i(?:n(?:to\b\W*?\b(?:dump|out)file|sert\b\W*?\binto|ner\b\W*?\bjoin)\b|(?:f(?:\b\W*?\(\W*?\bbenchmark|null\b)|snull\b)\W*?\()|print\b\W*?\@\@|cast\b\W*?\()|c(?:(?:ur(?:rent_(?:time(?:stamp)?|date|user)|(?:dat|tim)e)|h(?:ar(?:(?:acter)?_length|set)?|r)|iel(?:ing)?|ast|r32)\W*\(|o(?:(?:n(?:v(?:ert(?:_tz)?)?|cat(?:_ws)?|nection_id)|(?:mpres)?s|ercibility|alesce|t)\W*\(|llation\W*\(a))|d(?:(?:a(?:t(?:e(?:(_(add|format|sub))?|diff)|abase)|y(name|ofmonth|ofweek|ofyear)?)|e(?:(?:s_(de|en)cryp|faul)t|grees|code)|ump)\W*\(|bms_\w+\.\b)|(?:;\W*?\b(?:shutdown|drop)|\@\@version)\b|\butl_inaddr\b|\bsys_context\b|'(?:s(?:qloledb|a)|msdasql|dbo)'))" "phase:2,rev:'2',ver:'OWASP_CRS/2.2.9',maturity:'9',accuracy:'8',capture,t:none,t:urlDecodeUni,ctl:auditLogParts=+E,block,msg:'SQL Injection Attack',id:'950001',tag:'OWASP_CRS/WEB_ATTACK/SQL_INJECTION',tag:'WASCTC/WASC-19',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/CIE1',tag:'PCI/6.5.2',logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sql_injection_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-OWASP_CRS/WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{tx.0}
当我在java中使用它时,一些行被成功分开,但是一些行导致错误
Exception in thread "main" java.lang.StackOverflowError
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4235)
at java.util.regex.Pattern$BranchConn.match(Pattern.java:4095)
at java.util.regex.Pattern$CharProperty.match(Pattern.java:3362)
at java.util.regex.Pattern$Branch.match(Pattern.java:4131)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4185)
at java.util.regex.Pattern$Loop.match(Pattern.java:4312)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4244)
at java.util.regex.Pattern$BranchConn.match(Pattern.java:4095)
at java.util.regex.Pattern$CharProperty.match(Pattern.java:3362)
at java.util.regex.Pattern$Branch.match(Pattern.java:4131)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4185)
at java.util.regex.Pattern$Loop.match(Pattern.java:4312)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4244)
at java.util.regex.Pattern$BranchConn.match(Pattern.java:4095)
at java.util.regex.Pattern$CharProperty.match(Pattern.java:3362)
at java.util.regex.Pattern$Branch.match(Pattern.java:4131)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4185)
示例输入:
“世界”是美丽的“但我”看不到“它
预期产出:
The
"world \" beautiful"
but
i
"cannot see"
it
答案 0 :(得分:2)
你的正则表达式被破坏了:
(([\"]([^\\\"]|\\.)+[\"]|[^ ]+))+
#### ####### ###
| | ---------------- A dot
| ------------------------ Any character not "
----------------------------- A " (no need to put it in a character class)
此时我停止了进一步观察,因为我确信这不是你想要的。
顺便说一下,我建议先编写正则表达式,然后再进行引用(你可以自己编写一个工具来做到这一点,它纯粹是机械的:在\
之前添加一个"
和每\
,然后括在“”)。另外,不要对单个字符使用字符类。
事实上,您正在寻找的是单词或字符串。所以,你为什么不这么说呢。
您可以使用自上而下的方法:
REGEX = (WORD|STRING)
WORD = \w+ -- or \p{L} or something like that
STRING = "(SOMETHING)*"
SOMETHING = \\["\\]|[^\\"] -- an escaped quote, an escaped backslash or
-- something that is neither a backslash nor a quote
现在:
您可以单独测试重要的子正则表达式,例如STRING。原来我在我的第一个版本中有几个错误,这甚至在写不引用的时候!以java的形式编写/讨论这种正则表达式从一开始就几乎是不可能的。
答案 1 :(得分:2)
在Pattern
类(随Oracle的JRE,OpenJDK和许多其他JVM一起提供)的参考实现中,当重复模式时,使用递归 1 实现贪婪和惰性量词是非平凡的。因此,当输入字符串足够长时,您将遇到StackOverflowError
。
1 递归是一种快速但不可扩展的解决方案,允许在模式中进行回溯。更好的实现使用数据结构来存储回溯点 (它基本上将递归解决方案转换为带有堆栈的迭代解决方案。)
以下正则表达式应该有效:
"(?:\"(?:[^\"\\\\]++|\\\\.)*+\"|[^ \"]++)++"
好吧,正则表达式令人困惑的是2层转义:在Java字符串文字中转义并在正则表达式语法中转义。
打印字符串时的原始正则表达式。我的解释将基于原始正则表达式。
(?:"(?:[^"\\]++|\\.)*+"|[^ "]++)++
由于您只关心整个正则表达式匹配的内容,因此所有捕获组(pattern)
都已转换为非捕获组(?:pattern)
以提高效率。
第一个替代"(?:[^"\\]++|\\.)*+"
匹配带引号的字符串。
第二个备选[^ "]++
匹配不包含空格和双引号"
的字符序列。
(?:
" # Double quote
(?:
[^"\\]++ # A sequence of characters that are not " and \
| # OR
\\. # Escape sequence: \ followed by any character (except line terminators)
)*+ # Match 0 or more of the sequences above (allows empty string)
" # Double quote
|
[^ "]++
)++
由于正则表达式是为了不需要回溯而编写的,因此所有量词都具有占有性。由于Pattern
类使用循环实现占有量词,而不是像贪婪/惰性量词的情况那样递归,StackOverflowError
不会发生。
我通过编写正则表达式来消除回溯的需要,以便在第一次尝试时匹配正确的字符串:
由于[^"\\]
排除\
,我们无法从转义序列中“窃取”\
,或“窃取”"
并且搞砸了收尾报价,我们可以安全地向前推进,而无需回溯。这解释了占有量词[^"\\]++
。这里没有必要指定量词,但我这样做是为了减少分支的工作。
由于[^"\\]++
和\\.
都不能“窃取”"
并搞乱结束语,我们可以在没有回溯的情况下向前推进。这解释了占有量词(?:[^"\\]++|\\.)*+
[^ "]
无法启动带引号的字符串,也无法匹配空格(分隔符)。这就是我们可以使用占有量词的原因。
由于"(?:[^"\\]++|\\.)*+"
和[^ "]++
无法搞清楚彼此之间的匹配,我们可以使外部量词占有率最高。
首次尝试时未正确匹配的正则表达式示例,只有在^([bcd]+:[ab]+)+$
后才能获得正确的结果,而b:ab:a
等输入才会b:ab
。第一次迭代将匹配b:a
,这会导致第二次迭代失败,然后回溯并重试第一次迭代为{{1}},然后成功匹配整个字符串。
答案 2 :(得分:0)
感谢您的所有回复。我找到了自己的错误。实际的原因是stackoverflow不是我的正则表达式。我的正则表达式是正确的。我用eclipse进行编码。 stackoverflow的实际原因是我的堆栈大小。我的堆栈大小是1Mb。我在日食中增加了程序的堆栈大小,没有错误。
Java stack overflow error - how to increase the stack size in Eclipse?
更新:
无需更改堆栈大小。正如nhahtdh所述,我已将正则表达式更改为正则表达式,具有占有量词,并且没有 stackoverflow错误。
我的正则表达式现在 ("([^\\"]|\\.)++"|[^\s]++)
要详细了解占有量词follow this link。
答案 3 :(得分:-2)
首先要尝试的是increase the stack size。
如果这不起作用,您可能遇到了错误。您可以尝试different JVM并设置JVM以使用OpenJDK之外的其他内容来修改类库,并修改正则表达式以查看触发它的确切内容。