[英]Regular expression to match consecutive numbers
我正在嘗試從以下具有連續數字的字符串中提取部分:
word 7, word 8, word 9, word 14
所以我得到:
word 7, word 8, word 9
word 14
使用正則表達式。 我所做的是使用(word (?<num>\\d+),?\\s*)+
,然后檢查每次捕獲的數字。
是否可以使用正則表達式直接提取僅包含連續數字的部分?
由於非RegEx解決方案是可以接受的:
var data = "word 7, word 8, word 9, word 14";
// split the data into word and number
var dataCollection = data.Split(',').Select (d => new
{
word = d.Trim().Split(' ')[0],
number = int.Parse(d.Trim().Split(' ')[1])
}).ToList();
// store each set of consective results into a collection
List<string> resultsCollection = new List<string>();
var sb = new StringBuilder();
int i = 0;
while(i < dataCollection.Count ())
{
if(i > 0)
{
if(dataCollection[i].number == dataCollection[i-1].number + 1)
{
if(sb.Length > 0) sb.Append(", ");
}
else
{
resultsCollection.Add(sb.ToString());
sb.Clear();
}
}
sb.AppendFormat("{0} {1}", dataCollection[i].word, dataCollection[i].number);
i++;
}
resultsCollection.Add(sb.ToString());
對於您的測試數據, resultsCollection
將包含兩項:
單詞7,單詞8,單詞9
字14
僅使用正則表達式是不可能的,因為正則表達式只能描述正則語言 。
除其他限制外,常規語言不允許定義上下文,在您的情況下,這將是字符串中最新的遇到的數字。
有關語言和語法理論的更多信息,請參見Chomsky層次結構 。
或者,您可以使用:
string words = "word 7, word 8, word 9, word 14";
string[] splittedWords = Regex.Split(words, ", "); //Separating words.
List<string> sortedWords = new List<string>();
int currentWordNumber = 0, lastWordNumber = 0;
foreach (string sptw in splittedWords)
{
if (sortedWords.Count == 0) //No value has been written to the list yet, so:
{
sortedWords.Add(sptw);
lastWordNumber = int.Parse(sptw.Split(' ')[1]); //Storing the number of the word for checking it later.
}
else
{
currentWordNumber = int.Parse(sptw.Split(' ')[1]);
if (currentWordNumber == lastWordNumber + 1)
sortedWords[sortedWords.Count - 1] += ", " + sptw;
else
sortedWords.Add(sptw);
lastWordNumber = currentWordNumber; //Storing the number of the word for checking it later.
}
}
最后, sortedWords列表將具有:
"word 7, word 8, word 9"
"word 14"
LINQ非常適合各種序列。 它有許多有用的運算符,但您也可以定義自己的運算符。 使用方法如下:
"word 10, word 11, word 7, word 8, word 9, word 14, word 2"
.Split( new [] {", "}, StringSplitOptions.RemoveEmptyEntries)
.ToPartitionsOfConsecutiveValues(w => Int32.Parse(w.Split(' ').Last()))
.Select(sequence => String.Join(", ", sequence))
.ToArray()
.Dump("Array of strings");
Dump
來自LINQPad。
這是新的運算符:
public static class Partition {
public static IEnumerable<List<T>> ToPartitionsOfConsecutiveValues<T>(
this IEnumerable<T> source,
Func<T,int> valueSelector)
{
var lastValue = (int?)null;
List<T> lastList = null;
foreach (var item in source)
{
var value = valueSelector(item);
if (!(lastValue.HasValue))
{
lastList = new List<T>();
}
else if (lastValue.Value != value - 1)
{
yield return lastList;
lastList = new List<T>();
}
lastValue = value;
lastList.Add(item);
}
if (lastValue.HasValue) yield return lastList;
}
}
根據@LB的評論進行更新
如果LINQ運算符的具體類型越少越有用。 拔出使用項目類型( int
)的謂詞可以在其他情況下使用運算符。
這是相同的示例:
Func<String,Int32> IntSuffix = w => Int32.Parse(w.Split(' ').Last());
Func<String, String, Boolean> breakPredicate
= (prev, next) => IntSuffix(prev) != IntSuffix(next) - 1;
s.Split( new [] {", "}, StringSplitOptions.RemoveEmptyEntries)
.ToPartitionsOfSequences(breakPredicate)
.Select (sequence => String.Join(", ", sequence))
實現:
public static IEnumerable<List<T>> ToPartitionsOfSequences<T>(
this IEnumerable<T> source,
Func<T, T, Boolean> breakPredicate)
{
T lastItem = default(T);
List<T> lastList = null;
foreach (var item in source)
{
if (lastList == null)
{
lastList = new List<T>();
}
else if (breakPredicate(lastItem, item))
{
yield return lastList;
lastList = new List<T>();
}
lastItem = item;
lastList.Add(item);
}
if (lastList != null) yield return lastList;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.