理解这个正则表达式语句

6

我正在尝试详细了解这个正则表达式语句。它应该验证来自ASP.Net FileUpload控件的文件名,只允许jpeg和gif文件。它是由其他人设计的,我并不完全理解它。它在Internet Explorer 7.0中运行良好,但在Firefox 3.6中不起作用。

<asp:RegularExpressionValidator id="FileUpLoadValidator" runat="server" 
     ErrorMessage="Upload Jpegs and Gifs only." 
     ValidationExpression="^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))(.jpg|.JPG|.gif|.GIF)$"
     ControlToValidate="LogoFileUpload">
</asp:RegularExpressionValidator>

不确定为什么这个被踩了。 - Rob Levine
2
因为它要求别人替他完成任务,而不是教他如何完成任务。只有三个赞?我猜发一百万个“这个正则表达式是什么意思”的问题吧。 - Brian Leahy
我同意Brian的看法,这太荒谬了。 - Josh Stodola
Brian,那么你是在推荐人们阅读书籍而不是使用StackOverflow来获取答案吗? - myforums
我花了一些时间,但我找到了为什么它不能在Firefox中工作的原因。 Firefox v3.x不允许JavaScript从文件输入字段获取完整路径名,而这个特定的正则表达式期望看到完整路径名。 - myforums
5个回答

9
这里是简短的解释:
^               # match the beginning of the input
(               # start capture group 1
  (             #   start capture group 2
    [a-zA-Z]    #     match any character from the set {'A'..'Z', 'a'..'z'}
    :           #     match the character ':'
  )             #   end capture group 2
  |             #   OR
  (             #   start capture group 3
    \\{2}       #     match the character '\' and repeat it exactly 2 times
    \w+         #     match a word character: [a-zA-Z_0-9] and repeat it one or more times
  )             #   end capture group 3
  \$?           #   match the character '$' and match it once or none at all
)               # end capture group 1
(               # start capture group 4
  \\            #   match the character '\'
  (             #   start capture group 5
    \w          #     match a word character: [a-zA-Z_0-9] 
    [\w]        #     match any character from the set {'0'..'9', 'A'..'Z', '_', 'a'..'z'}
    .*          #     match any character except line breaks and repeat it zero or more times
  )             #   end capture group 5
)               # end capture group 4
(               # start capture group 6
  .             #   match any character except line breaks
  jpg           #   match the characters 'jpg'
  |             #   OR
  .             #   match any character except line breaks
  JPG           #   match the characters 'JPG'
  |             #   OR
  .             #   match any character except line breaks
  gif           #   match the characters 'gif'
  |             #   OR
  .             #   match any character except line breaks
  GIF           #   match the characters 'GIF'
)               # end capture group 6
$               # match the end of the input

编辑

由于一些评论的要求,上述内容是我写的一个小工具生成的。你可以在这里下载它:http://www.big-o.nl/apps/pcreparser/pcre/PCREParser.html (警告:正在大力开发中!)

编辑2

它将匹配以下字符串:

x:\abc\def\ghi.JPG
c:\foo\bar.gif
\\foo$\baz.jpg

以下是1、4和6组的单独匹配情况:
group 1 | group 4      | group 6
--------+--------------+--------
        |              |
 x:     | \abc\def\ghi | .JPG
        |              |
 c:     | \foo\bar     | .gif
        |              |
 \\foo$ | \baz         | .jpg
        |              |

请注意,它也会匹配像c:\foo\bar@gif这样的字符串,因为DOT可以匹配任何字符(除了换行符)。但是它将拒绝像c:\foo\bar.Gif这样的字符串(gif中有大写字母G)。

我可以不知情地问一下,你用什么工具做的这个? - Skilldrick
Bart K. 请问您能否发布一个允许进行此类解析的URL? - myforums
+1 详细!我也想知道这是否是由工具生成的。 - Pharabus
好在我重新加载了,否则我就会继续做这件可恶的事情了。+++ - user1228
Bart K. 我理解每个元素,但它们并不完全相互关联。 - myforums

4

这是一个不好的正则表达式。

^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))(.jpg|.JPG|.gif|.GIF)$

让我们逐步来做。

([a-zA-Z]:)

这需要文件路径以驱动器字母开头,例如C:D:等。

(\\{2}\w+)\$?)

\\{2} 表示反斜杠重复两次(请注意需要转义 \),接着是一些字母数字字符(\w+),然后可能会有一个美元符号(\$?)。这是 UNC 路径的主机部分。

([a-zA-Z]:)|(\\{2}\w+)\$?)
< p > < code > |

这里的|表示“或者”。因此,路径可以以驱动器字母开头,也可以是UNC路径。恭喜你成功地淘汰了非Windows用户。

(\\(\w[\w].*))

这应该是路径的目录部分,但实际上是两个字母数字后跟任何非换行符(.*),比如\ab!@#*(#$*)

这部分的正则表达式应为(?:\\\w+)+

(.jpg|.JPG|.gif|.GIF)$

这意味着路径的最后3个字符必须是jpgJPGgifGIF。请注意,.不是一个点,而是匹配除了\n以外的任何字符,因此像haha.abcgifmalicious.exe\0gif这样的文件名也可以通过检查。 这部分的正确正则表达式应该是\.(?:jpg|JPG|gif|GIF)$ 综上所述,
^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))(.jpg|.JPG|.gif|.GIF)$

将匹配

D:\foo.jpg
\\remote$\dummy\..\C:\Windows\System32\Logo.gif
C:\Windows\System32\cmd.exe;--gif

并且会失败

/home/user/pictures/myself.jpg
C:\a.jpg
C:\d\e.jpg

适当的正则表达式是/\.(?:jpg|gif)$/i,并检查上传的文件在服务器端是否真的是图像。

哇!非常感谢您提供的详细信息。这正是我一直在寻找的。解决了我的问题。不过我仍然很好奇为什么原始代码在Firefox中无法运行。也许这是一个单独的问题,但可能与主题并不太相关。 - myforums
抱歉,刚刚发现''无法用于'C:\doc\My Pictures\cat-fish.gif'。 - myforums

1

它将文件名拆分为驱动器字母、路径、文件名和扩展名部分。

很可能IE使用反斜杠,而FireFox使用斜杠。尝试用 [\\/] 替换 \\\\ 部分,这样表达式就可以接受斜杠和反斜杠了。


不行。用[\/]替换\也没有帮助。在Firefox中仍然无法正常工作。 - myforums

0

Expresso上,这是Expresso的说法:

/// 正则表达式的描述: /// /// 行首或字符串开头 /// [1]:一个编号的捕获组。[([a-zA-Z]:)|(\\{2}\w+)\$?] /// 从2个备选项中选择 /// [2]:一个编号的捕获组。[[a-zA-Z]:] /// [a-zA-Z]: /// 此类中的任何字符:[a-zA-Z] /// : /// (\\{2}\w+)\$? /// [3]:一个编号的捕获组。[\\{2}\w+] /// \\{2}\w+ /// 字面上的\,恰好重复2次 /// 字母数字,一次或多次重复 /// 字面上的$,零次或一次重复 /// [4]:一个编号的捕获组。[\\(\w[\w].*)] /// \\(\w[\w].*) /// 字面上的\ /// [5]:一个编号的捕获组。[\w[\w].*] /// \w[\w].* /// 字母数字 /// 此类中的任何字符:[\w] /// 任何字符,任意次数重复 /// [6]:一个编号的捕获组。[.jpg|.JPG|.gif|.GIF] /// 从4个备选项中选择 /// .jpg /// 任何字符 /// jpg /// .JPG /// 任何字符 /// JPG /// .gif /// 任何字符 /// gif /// .GIF /// 任何字符 /// GIF /// 行尾或字符串结尾
希望这能有所帮助, 最好的问候, 汤姆。

0
你可能需要实现服务器端验证。看看这篇文章。 解决 ASP.NET 验证的挑战 此外,有一些很好的在线工具可以创建或解释正则表达式。但我怀疑问题不在于表达式。

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