正则表达式解析FTP服务器列表C#

时间:2017-03-22 15:59:47

标签: c# regex

我正在使用Regex列表来解析FTP服务器列表。我对Regex一点都不好,这是我在线收集的正则表达式列表,用于解析各种服务器FTP输出:

private static readonly string[] DirectoryParseFormats = 
        {
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)",
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)",
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)",
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)",
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})(\\s+)(?<size>(\\d+))(\\s+)(?<ctbit>(\\w+\\s\\w+))(\\s+)(?<size2>(\\d+))\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{2}:\\d{2})\\s+(?<name>.+)",
            "(?<timestamp>\\d{2}\\-\\d{2}\\-\\d{2}\\s+\\d{2}:\\d{2}[Aa|Pp][mM])\\s+(?<dir>\\<\\w+\\>){0,1}(?<size>\\d+){0,1}\\s+(?<name>.+)"
        };

现在我偶然发现了来自奇数FTP服务器的输出。奇怪的是,服务器出于某种原因输出文件名和文件夹名。

无论如何,我想为这个字符串设置类似的RegEx,理想情况下引入folder名称将其分开,服务器返回的字符串是内部管道|

|-rw-rw-rw- 1 generic 235 Mar 22 11:21 fromDoder/DOD997ABCD.20170322112114159.1961812284.txt|

修改

这是我用来迭代regex表达式的C#代码,用于选择与FTP服务器输出匹配的代码。然后我用它来解析文件名和类型

// Use our regex library to parse
match = DirectoryParseFormats.Select(dpf => new Regex(dpf).Match(raw)).FirstOrDefault(m => m.Success); 

if (match == null) throw new Exception($"Can't parse FTP directory list item. raw item: |{raw}|, whole response: |{response}|");

// If not directory - this is file
var dir = match.Groups["dir"].Value;
if (dir == string.Empty || dir == "-") list.Add(match.Groups["name"].Value);

编辑2:

total 0
drw-rw-rw-   1 user     group           0 Apr 23  2016 .
drw-rw-rw-   1 user     group           0 Apr 23  2016 ..

编辑3:

var hintRegex = @"^
(?<dir>[-d])
(?<permission>(?:[-r][-w][-xs]){3})
\s+\d+
\s+\w+
(?:\s+\w+)?
\s+(?<size>\d+)
\s+(?<timestamp>\w+\s+\d+(?:\s+\d+(?::\d+)?))
\s+(?!(?:\.|\.\.)\s*$)(?<name>.+?)\s*
$";

            Match match = new Regex(hintRegex).Match("-rw-r--r-- 1 ftp ftp           1079 Apr 06  2017 LEANCOR_040617084839.txt");

            if (!match.Success) Debug.WriteLine("Doesn't match");

2 个答案:

答案 0 :(得分:1)

给定字符串输入的正则表达式如下:

(?<permission>([\\-rwxs]+){3})\\s+\\d+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{1,2})\\s+(?<folder>\\w+\\/)?(?<name>.+)

在线正则表达式测试包括正则表达式模式和给定的输入字符串如下图所示。

See the online regex test output given below

答案 1 :(得分:1)

由于您的模式看起来像是在尝试匹配ls -l的输出,并且您提到它是一个列表命令。我假设是这样。

我可以从您的代码中收集的主要问题是您错过了多行标记(RegexOptions.Multiline)。

你的正则表达式似乎是正确的,我只做了一些改动。这里有一些间距(如果使用扩展标志,它仍然有效)。

^
(?<dir>[-d])
(?<permission>(?:[-r][-w][-xs]){3})
\s+\d+
\s+\w+
(?:\s+\w+)?
\s+(?<size>\d+)
\s+(?<timestamp>\w+\s+\d+(?:\s+\d+(?::\d+)?))
\s+(?!(?:\.|\.\.)\s*$)(?<name>.+?)\s*
$

<强> Here's a live preview.

您可以通过执行以下操作进行测试:

string pattern = @"^(?<dir>[-d])(?<permission>(?:[-r][-w][-xs]){3})\s+\d+\s+\w+(?:\s+\w+)?\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+(?:\s+\d+(?::\d+)?))\s+(?!(?:\.|\.\.)\s*$)(?<name>.+?)\s*$";
Regex re = new Regex(pattern, RegexOptions.Multiline);

string source = @"
-rwxr-xr-x 1 root  46789 Feb  7 23:15 certbot-auto
drwxr-xr-x 2 root   4096 Mar 22 16:29 test dir
drwxr-xr-x 4 root   4096 Feb 10 15:50 www
-rw-rw-rw- 1 generic 235 Mar 22 11:21 fromDoder/DOD997ABCD.20170322112114159.1961812284.txt
-rw-rw-rw- 1 cmuser cmuser 904 Mar 23 15:04 20170323110427785_3741647.edi
drw-rw-rw- 1 user   group    0 Apr 23  2016 .
drw-rw-rw- 1 user   group    0 Apr 23  2016 ..
drw-rw-rw- 1 user   group    0 Apr 23  2016 .cache
drw-rw-rw- 1 user   group    0 Apr 23  2016 .bashrc
";

MatchCollection matches = re.Matches(source);

Console.WriteLine(matches.Count);

foreach (Match match in matches)
{
    Console.WriteLine(match.Groups["dir"]);
    Console.WriteLine(match.Groups["permission"]);
    Console.WriteLine(match.Groups["size"]);
    Console.WriteLine(match.Groups["timestamp"]);
    Console.WriteLine(match.Groups["name"]);
    Console.WriteLine();
}

请注意,source的内容只是我服务器上ls -l输出的已编辑版本(添加了您的示例)。因此,如果我的假设是正确的,那么你应该对它很熟悉。

修改:根据您的评论,您只需删除其中一个\s+\w+(我已经更新了以上所有内容以反映这一点。)