我从文本流中提取数据,这是一种数据结构
/1-<id>/<recType>-<data>..repeat n times../1-<id>/#-<data>..repeat n times..
在上面,&#34; / 1&#34;字段在记录数据之前,然后可以包含任意数量的以下字段,每个字段可以选择recType
从2到9(同样,每个字段以&#34; /&#34开头)
例如:
/1-XXXX/2-YYYY/9-ZZZZ/1-AAAA/3-BBBB/5-CCCC/8=NNNN/9=DDDD/1-QQQQ/2-WWWW/3=PPPP/7-EEEE
所以,上面有三组数据
1=XXXX 2=YYYY 9=ZZZZ
1=AAAA 3=BBBB 5=CCCC 8=NNNN 9=DDDD
1=QQQQ 2=WWWW 3=PPPP 7=EEEE
数据是为了简单起见,我确信它只包含[A-Z0-9。 ]但可以是可变长度(不仅仅是4个字符)
现在,以下表达式有效,但它只捕获每个组的前2个字段而没有剩余的字段......
/1-(?'fld1'[A-Z]+)/((?'fldNo'[2-9])-(?'fldData'[A-Z0-9\. ]+))
我知道我某处需要某种quantifier
,但我不知道放在哪里或放在哪里。
答案 0 :(得分:1)
您可以使用正则表达式来匹配这些块,使用2个.NET正则表达式功能:1)捕获集合和2)模式中具有相同名称的多个捕获组。然后,我们需要一些Linq魔法将捕获的数据合并到一个列表列表中:
(?<fldNo>1)-(?'fldData'[^/]+)(?:/(?<fldNo>[2-9])[-=](?'fldData'[^/]+))*
<强>详情:
(?<fldNo>1)
- 小组fldNo
匹配1
-
- 连字符(?'fldData'[^/]+)
- Group&#34; fldData&#34;捕获除/
(?:/(?<fldNo>[2-9])[-=](?'fldData'[^/]+))*
- 零个或多个序列:
/
- 文字/
(?<fldNo>[2-9])
- 2
至9
位数(Group&#34; fldNo&#34;)[-=]
- -
或=
(?'fldData'[^/]+)
- 除/
以外的1个字符(Group&#34; fldData&#34;)请参阅regex demo,结果:
请参阅C# demo:
using System;
using System.Linq;
using System.Text.RegularExpressions;
public class Test
{
public static void Main()
{
var str = "/1-XXXX/2-YYYY/9-ZZZZ/1-AAAA/3-BBBB/5-CCCC/8=NNNN/9=DDDD/1-QQQQ/2-WWWW/3=PPPP/7-EEEE";
var res = Regex.Matches(str, @"(?<fldNo>1)-(?'fldData'[^/]+)(?:/(?<fldNo>[2-9])[-=](?'fldData'[^/]+))*")
.Cast<Match>()
.Select(p => p.Groups["fldNo"].Captures.Cast<Capture>().Select(m => m.Value)
.Zip(p.Groups["fldData"].Captures.Cast<Capture>().Select(m => m.Value),
(first, second) => first + "=" + second))
.ToList();
foreach (var t in res)
Console.WriteLine(string.Join(" ", t));
}
}
答案 1 :(得分:0)
答案 2 :(得分:0)
单个正则表达式不是执行此操作的最佳工具(至少以这种方式使用)。主要原因是因为您的流中包含可变数量的条目,并且不支持使用可变数量的捕获组。我还注意到一些值有&#34; =&#34;它们之间以及破折号,你当前的正则表达式都没有解决。
当您尝试将量词添加到捕获组时,问题就出现了 - 该组只会记住它捕获的最后一个东西,因此如果添加量词,它将最终捕获第一个和最后一个字段,而忽略所有字段其余的人。所以这样的事情不会起作用:
\/1-(?'fld1'[A-Z]+)(?:\/(?'fldNo'[2-9])[-=](?'fldData'[A-Z]+))+
如果您的流的长度都相同,那么可以使用单个正则表达式,但是有一种方法可以使用foreach循环来执行此操作,其中使用更简单的正则表达式处理流的每个部分(因此它会验证你的流也一样!)
现在我不确定您在使用这种语言时使用的是哪种语言,但我认为这是一种PHP解决方案,可以满足您的需求。
function extractFromStream($str)
{
/*
* Get an array of [num]-[letters] with explode. This will make an array that
* contains [0] => 1-AAAA, [1] => 2-BBBB ... etc
*/
$arr = explode("/", substr($str, 1));
$sorted = array();
$key = 0;
/*
* Sort this data into key->values based on numeric ordering.
* If the next one has a lower or equal starting number than the one before it,
* a new entry will be created. i.e. 2-aaaa => 1-cccc will cause a new
* entry to be made, just in case the stream doesn't always start with 1.
*/
foreach ($arr as $value)
{
// This will get the number at the start, and has the added bonus of making sure
// each bit is in the right format.
if (preg_match("/^([0-9]+)[=-]([A-Z]+)$/", $value, $matches)) {
$newKey = (int)$matches[1];
$match = $matches[2];
} else
throw new Exception("This is not a valid data stream!");
// This bit checks if we've got a lower starting number than last time.
if (isset($lastKey) && is_int($lastKey) && $newKey <= $lastKey)
$key += 1;
// Now sort them..
$sorted[$key][$newKey] = $match;
// This will be compared in the next iteration of the loop.
$lastKey = $newKey;
}
return $sorted;
}
以下是如何使用它...
$full = "/1-XXXX/2-YYYY/9-ZZZZ/1-AAAA/3-BBBB/5-CCCC/8=NNNN/9=DDDD/1-QQQQ/2-WWWW/3=PPPP/7-EEEE";
try {
$extracted = extractFromStream($full);
$stream1 = $extracted[0];
$stream2 = $extracted[1];
$stream3 = $extracted[2];
print "<pre>";
echo "Full extraction: \n";
print_r($extracted);
echo "\nFirst Stream:\n";
print_r($stream1);
echo "\nSecond Stream:\n";
print_r($stream2);
echo "\nThird Stream:\n";
print_r($stream3);
print "</pre>";
} catch (Exception $e) {
echo $e->getMessage();
}
这将打印
Full extraction:
Array
(
[0] => Array
(
[1] => XXXX
[2] => YYYY
[9] => ZZZZ
)
[1] => Array
(
[1] => AAAA
[3] => BBBB
[5] => CCCC
[8] => NNNN
[9] => DDDD
)
[2] => Array
(
[1] => QQQQ
[2] => WWWW
[3] => PPPP
[7] => EEEE
)
)
First Stream:
Array
(
[1] => XXXX
[2] => YYYY
[9] => ZZZZ
)
Second Stream:
Array
(
[1] => AAAA
[3] => BBBB
[5] => CCCC
[8] => NNNN
[9] => DDDD
)
Third Stream:
Array
(
[1] => QQQQ
[2] => WWWW
[3] => PPPP
[7] => EEEE
)
因此,您可以看到数字作为数组键,以及它们对应的值,现在可以轻松访问以进行进一步处理。我希望这可以帮助你:)