PHP/Regex:检查输入的格式

PHP/Regex:检查输入的格式,php,regex,Php,Regex,我有一个输入字段,用户可以在其中写入一些链接,在提交后,我想检查此输入的正确结构 允许的结构: Google: http://google.com YouTube: http://youtube.com Stackoverflow: http://stackoverflow.com/ 我的正则表达式不像我想象的那样工作 (.*)\:(\s?)(.*)\n 正则表达式应在preg_匹配函数中使用 编辑(从注释中移动): 我的代码: $input = 'Google: http://googl

我有一个输入字段,用户可以在其中写入一些链接,在提交后,我想检查此输入的正确结构

允许的结构:

Google: http://google.com
YouTube: http://youtube.com
Stackoverflow: http://stackoverflow.com/
我的正则表达式不像我想象的那样工作

(.*)\:(\s?)(.*)\n
正则表达式应在preg_匹配函数中使用


编辑(从注释中移动): 我的代码:

$input = 'Google: http://google.com
YouTube: http://youtube.com
wrong
Stackoverflow: http://stackoverflow.com/';
if (preg_match_all('/(.*?)\:\s?(.*?)$/m', $input))
{
    echo 'ok';
}
else
{
    echo 'no';
}

我得到“ok”。但是,由于“错误”不是正确的模式,我希望答案是“否”。

你的问题有些模糊。要匹配url,您只需执行以下操作:

^[^:]+:\s*https?:\/\/[^\s]+$
# match everything except a colon, then followed by a colon
# followed by whitespaces or not
# match http/https, a colon, two forward slashes literally
# afterwards, match everything except a whitespace one or unlimited times
# anchor it to start(^) and end($) (as wanted in the comment)

请参见a。

有几件事需要纠正:

  • 星号运算符是贪婪的。在您的情况下,您希望它是懒惰的,所以在这两种情况下都在它后面添加一个问号 你可能对保持中间的分隔空间不感兴趣,所以不要在它周围放置托架;<李>
  • 如果希望处理所有行,则需要使用preg_match_all而不是preg_match
  • 除非您确定最后一行以新行结尾,否则您需要测试带美元符号的字符串的结尾
  • 由于最后一个测试需要括号,请使用
    ?:
    使其不捕获,因为您对保留新行字符不感兴趣
  • 有些系统在每个
    \r
    之前都有
    \n
    ,因此您应该添加它,否则它会进入您的一个捕获组。或者,将
    m
    修饰符与$(行尾)结合使用,忘记换行符
  • 由于冒号也出现在URL中,您至少应该测试该冒号,否则缺少第一个冒号(在站点名称之后)将使“http”成为站点名称的一部分
这导致以下情况:

$input =
"Google: http://google.com
YouTube: http://youtube.com
Stackoverflow: https://stackoverflow.com/";

$result = preg_match("/(.*?)\:\s?(\w?)\:(.*?)$/m", $input, $matches);
echo $result ? "matched!"
print_r ($matches);
产出:

Array
(
    [0] => Array
        (
            [0] => Google: http://google.com
            [1] => YouTube: http://youtube.com
            [2] => Stackoverflow: https://stackoverflow.com/
        )

    [1] => Array
        (
            [0] => Google
            [1] => YouTube
            [2] => Stackoverflow
        )

    [2] => Array
        (
            [0] => http://google.com
            [1] => http://youtube.com
            [2] => https://stackoverflow.com/
        )
)
第一个元素具有完整的匹配项(行),第二个元素具有第一个捕获组的匹配项,最后一个元素具有第二个捕获组的内容

请注意,以上内容不会验证URL。这是一个独立的主题。看过

编辑 如果您想确定整个输入的格式是否正确,则可以使用上面的表达式,但可以使用
preg\u replace
。用空格替换所有好的行,修剪换行的最终结果,并测试是否有剩余内容:

$result =  trim(preg_replace("/(.*?)\:\s?(\w*?):(.*?)$/m", "", $input));
if ($result == "") {
    echo "It matches the pattern";
} else {
    echo "It does not match the pattern. Offending lines:
         " . $result;
}

上述情况将允许输入中出现空行。

您可以通过查找不符合要求的行来实现这一点

'~(.*):\s?(.*)$~m'
一起使用!预匹配
。请参阅打印“否”:


请注意,您不需要转义
符号。另外,我建议在末尾切换到贪心点匹配,因为这将迫使引擎一次抓取所有行,直到最后,然后在那里检查行的结尾,因此正则表达式将更有效。为了提高效率,您也可以尝试将第一个
*?
替换为
[^:::]*

所以最后不要
www
,总是
.com
?不,它应该是可变的。我看到的唯一一件事是您需要
\n
。实际上,您应该使用
m
修饰符执行
$
。你想让你的第一个
(.*)
不贪婪,否则它将匹配url中的
。哦,使用
preg\u match\u all
而不是
preg\u match
,否则你将匹配第一个而不匹配其他内容。精确的URL匹配很复杂:我不想获取URL或字符串的其他内容。我想检查一下结构是否符合要求。@Xübecks:你需要确定锚定点,看看我更新的答案。我想你理解我错了。我只想检查一下结构是否符合要求。最后,我对我的问题说了更多。你的“编辑”解决了我的问题。对不起,我说的太多了。谢谢
$input = 'Google: http://google.com
YouTube: http://youtube.com
wrong
Stackoverflow: http://stackoverflow.com/';
if (!preg_match('~(.*?):\s?(.*)$~m', $input)) {
    echo 'ok';
}
else {
    echo 'no';
}