我想使用正则表达式来验证用户输入。我想允许字母、数字、空格、逗号、撇号、句号、感叹号和问号的任意组合,但我还想将输入限制为 4000 个字符。我想出了以下正则表达式来实现这一点: /^([a-z]|[0-9]| |,|'|\.|!|\?){1,4000}$/i 。
但是,当我尝试使用此正则表达式在 PHP 中使用 preg_match() 测试主题时,我收到警告:PHP Warning: preg_match(): Compilation failed: regular expression is too large at offset 37 并且主题未通过测试。
我觉得这很奇怪,因为如果我使用无限量词,测试就会顺利通过(我在下面演示了这种情况)。
为什么将重复次数限制为 4000 次是个问题,但无限次重复却不是?
regex-test.php:
<?php
$infinite = "/^([a-z]|[0-9]| |,|'|\.|!|\?)*$/i"; // Allows infinite repetition
$fourk = "/^([a-z]|[0-9]| |,|'|\.|!|\?){1,4000}$/i"; // Limits repetition to 4000
$string = "I like apples.";
if ( preg_match($infinite, $string) ){
echo "Passed infinite repetition. \n";
}
if ( preg_match($fourk, $string) ){
echo "Passed maximum repetition of 4000. \n";
}
?>
echo :
Passed infinite repetition
PHP Warning: preg_match(): Compilation failed: regular expression is too large at offset 37 in regex-test.php on line 16
最佳答案
错误是由于其 LINK_SIZE,偏移值将编译后的模式大小限制为 64K。这是预期的行为,如下所述,这不是因为重复限制,也不是因为编译时模式的解释方式。
正如 Alan Moore 在 his answer 中指出的那样, 所有字符都应该在相同的 character class 中.我比较激进,所以请允许我说这种模式如此是错误的,这让我感到畏缩。
-无意冒犯,我们大多数人也尝试过一次。这只是试图强调绝不应使用此类结构。
(x|y|z){1,4000} 中有 3 个常见的陷阱:
|s)添加回溯状态。尽量减少它们是一个很好的做法。在这种情况下,正则表达式 ^[ !',.0-9?A-Z]{1,4000}$/i 将完全匹配,不仅避免了错误,而且证明效果更好表现。From "Handling Very Large Patterns" in pcrebuild man page:
Within a compiled pattern, offset values are used to point from one part to another (for example, from an opening parenthesis to an alternation metacharacter). By default, in the 8-bit and 16-bit libraries, two-byte values are used for these offsets, leading to a maximum size for a compiled pattern of around 64K.
这意味着编译模式为交替中的每个子模式、组的每次重复存储一个偏移值。在这种情况下,偏移量不会为编译模式的其余部分留下任何内存。
This is more clearly expressed in a comment in pcre_internal.h from the PHP dist:
PCRE keeps offsets in its compiled code as 2-byte quantities (always stored in big-endian order) by default. These are used, for example, to link from the start of a subpattern to its alternatives and its end. The use of 2 bytes per offset limits the size of the compiled regex to around 64K, which is big enough for almost everybody.
使用 pcretest ,我得到以下信息:
PCRE version 8.37 2015-04-28
/^([a-z]|[0-9]| |,|'|\.|!|\?){1,575}$/i
Failed: regular expression is too large at offset 36
/^([a-z]|[0-9]| |,|'|\.|!|\?){1,574}$/i
Memory allocation (code space): 65432
关于PCRE中的其他大小限制,可以查看this post of mine .
LINK_SIZE如果我们有真正的理由使用一个巨大的模式,并且这个模式无论如何都不能进一步简化,那么链接的大小就可以增加。但是,您只能通过自己重新编译 PHP 来实现此目的(因此,您的代码从现在起将无法移植)。如果别无选择,这应该是最后的手段。
Also commented in pcre_internal.h:
The macros are controlled by the value of
LINK_SIZE. This defaults to 2 in the config.h file, but can be overridden by using-Don the command line. This is automated on Unix systems via the "configure" command.
PCRE 链接大小可以配置为 3 或 4:
./configure -DLINK_SIZE=4
但请记住,较长的偏移量需要额外的数据,并且它会减慢对 preg_* functions 的所有调用.
如果您自己编译 PHP,请参阅 Installation on Unix systems或 Build your own PHP on Windows .
关于PHP - 为什么我被警告我的正则表达式太大?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33976303/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?