PHP preg_match 在处理换行符时无法正常工作

6

我有这个好用的 preg_match 正则表达式:

if(preg_match ("%^[A-Za-z0-9ążśźęćń󳥯ŚŹĘĆŃÓŁ\.\,\-\?\!\(\)\"\ \/\t\/\n]{2,50}$%", stripslashes(trim($_POST['x']))){...}

希望在最终发布的文本内容中使用所有字符。问题是,尽管有\n,但函数仍无法处理我的文章中的换行符。因此,以下语法:

foo

bar

将无法正常工作。 有人知道为什么这个函数不能正常工作吗?

非常感谢您的帮助。


你尝试过使用 /m 标志吗? - Quijote Shin
m标志有效。不过Klaar先完成了。 - aln447
@aln447:不,它不起作用。如果使用m修饰符,preg_match仅在字符串中的一行匹配模式时才会成功(请尝试使用一个包含允许字符的第一行和一个包含禁止字符的第二行)。你的问题可能是你的字符串使用了Windows换行序列\r\n(CRLF),因为\r不在你的字符类中,所以它不起作用。 - Casimir et Hippolyte
1个回答

5

默认情况下,使用包含 ^$ 的模式的 preg_match() 将考虑整个字符串,即使它包含换行符。

可以使用 模式修饰符 更改此行为,我将列出适用于此主题的修饰符:

  • s (PCRE_DOTALL):默认情况下,点号(.)不会匹配换行符,但是使用修饰符s后会匹配。然而,字符类(例如[a-z][^a-z])从来不会将换行符视为特殊字符,因此这个修饰符对它们的行为没有影响,就像对点号(.)一样。

  • m (PCRE_MULTILINE):默认情况下,起始锚点(^)和结束锚点($)将匹配整个字符串的开头和结尾,即使该字符串包含换行符。然而,当使用这个修饰符时,preg函数允许将由换行符分隔的每个部分都视为一个完整的字符串,因此"foo\nbar\nbar"将在与模式/^[a-z]$/m匹配时产生三个匹配项(1: foo, 2: bar, 3: bar),而不仅仅是一个(1: foo\nbar\bar),就像没有使用m修饰符时一样:/^[a-z]$/

  • D (PCRE_DOLLAR_ENDONLY):默认情况下,结束锚点($)不仅会匹配字符串的最后一个字符,而且会匹配位于尾随换行符之前的位置(尾随意味着在字符串的最后)。要撤消这种行为并使其非常严格地仅匹配字符串结尾,请使用这个模式修饰符。

你的问题:

if(preg_match("%^[A-Za-z0-9ążśźęćń󳥯ŚŹĘĆŃÓŁ\.\,\-\?\!\(\)\"\ \/\t\/\n]{2,50}$%m", stripslashes(trim($_POST['x']))){...}

除了您的模式不需要转义字符\-^(仅在字符类的开头)和](仅当不在字符类的开头时),我没有看到太多问题,但PHP文档说这样做并不违规。

然而,您的文本片段可能包含以\r\n形式出现的换行符,由于您的模式的字符类中不包括\r,因此它将无法匹配。

由于我的原始帖子提到了使用Patter Modifier m,而您回复说那个方法可行,我想知道真正的问题可能是什么。


抱歉,但是你的回答完全是错误的。修饰符 m 不允许匹配跨越多行(在这个上下文中,“multiline”一词有点误导)。m 修饰符的作用只是将 ^$ 锚点的含义从字符串的开头和结尾改变为行的开头和结尾。 - Casimir et Hippolyte
@CasimiretHippolyte:当然,你是对的!我已经重写了我的答案,以更好地反映Pattern Modifiers的真相以及它们如何影响preg函数的行为。不过,我仍然想知道,我的错误答案可能如何帮助OP。 - klaar
OP认为你的错误答案是正确的,因为他找到了一个与模式匹配的字符串(即:foo),这个字符串应该通过检查(他没有问问题或测试其他字符串,混合允许字符和不允许字符的行,这些行不应该通过)。但是这个模式并没有检查整个字符串。 - Casimir et Hippolyte
那么你们提出的实际正确处理该问题的方式是什么? 所提供的答案对我确实有帮助,因此我接受了它。我不是 PHP 专业人士。 - aln447
@aln447 你能检查一下你想要匹配模式的字符串,看看是否存在回车符(\r)?因为这个字符可能不会被包含在你提供的字符类中而无法匹配。这是我目前唯一的猜测。你可以使用任何半高级的编辑器,比如Notepad++,并打开显示所有字符的功能(包括空格、制表符和换行符)。 - klaar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接