我們需要在C#中提取和操作字符串。淨。要求是 - 我們有一個字符串在C#中提取和操縱字符串.net
($名稱$ :('喬治')和$ phonenumer $ :('456456')和 $ EMAILADDRESS $ :(「[email protected]」))
我們需要提取的字符之間的字符串 - $
因此,在最後,我們需要得到一個包含字符串列表 - 名,PHONENUMBER,EMAILADDRESS。
這樣做的理想方法是什麼?是否有任何可用於此的開箱即用功能?
問候,
約翰
我們需要在C#中提取和操作字符串。淨。要求是 - 我們有一個字符串在C#中提取和操縱字符串.net
($名稱$ :('喬治')和$ phonenumer $ :('456456')和 $ EMAILADDRESS $ :(「[email protected]」))
我們需要提取的字符之間的字符串 - $
因此,在最後,我們需要得到一個包含字符串列表 - 名,PHONENUMBER,EMAILADDRESS。
這樣做的理想方法是什麼?是否有任何可用於此的開箱即用功能?
問候,
約翰
最簡單的方法是使用正則表達式來匹配$
之間的所有非空白字符:
var regex=new Regex(@"\$\w+\$");
var input = "($name$:('George') AND $phonenumer$:('456456') AND $emailaddress$:(\"[email protected]\"))";
var matches=regex.Matches(input);
這將返回一組匹配項。每個匹配的.Value
屬性包含匹配的字符串。使用\$
是因爲$
在正則表達式中有特殊含義 - 它匹配字符串的末尾。 \w
表示非空白字符。 +
表示一個或多個。
由於這是一個集合,你可以使用LINQ它來獲得例如一個數組中的值:
var values=matches.OfType<Match>().Select(m=>m.Value).ToArray();
該數組將包含價值$name$
,$phonenumer$
,$emailaddress$
。
捕獲的名字
您可以指定在上述模式分類,並附名給他們。例如,您可以將字段名稱值:
var regex=new Regex(@"\$(?<name>\w+)\$");
var names=regex.Matches(input)
.OfType<Match>()
.Select(m=>m.Groups["name"].Value);
這將返回name,phonenumer,emailaddress
。圓括號用於分組。(?<somename>pattern)
用來名稱附加到組
提取物這兩個名字和值
您也可以捕捉字段值並提取它們作爲一個單獨的領域。獲得字段名稱和值後,可以將其返回,例如作爲對象或匿名類型。
在這種情況下,模式更加情結:
@"\$(?<name>\w+)\$:\(['""](?<value>.+?)['""]\)"
括號逃脫,因爲我們希望他們匹配的值。在值中使用'
和"
字符,因此['"]
用於指定字符的選擇。該模式是一個文字字符串(即以@開頭),因此雙引號必須轉義:['""]
。任何字符都必須匹配.+
,但僅限於.+?
中的下一個字符。如果沒有?
,模式.+
會將所有內容都匹配到字符串的末尾。
把這個在一起:
var regex = new Regex(@"\$(?<name>\w+)\$:\(['""](?<value>.+?)['""]\)");
var myValues = regex.Matches(input)
.OfType<Match>()
.Select(m=>new { Name=m.Groups["name"].Value,
Value=m.Groups["value"].Value
})
.ToArray()
把它變成一本字典
相反的ToArray()
您可以將對象與.ToDictionary(it=>it.Name,it=>it.Value)
轉換成字典,ToDictionary()
,例如。你可以省略選擇步驟並且從比賽本身詞典:
var myDict = regex.Matches(input)
.OfType<Match>()
.ToDictionary(m=>m.Groups["name"].Value,
m=>m.Groups["value"].Value);
正則表達式是一般快,因爲它們不拆分字符串。該模式轉換爲高效的代碼,用於解析輸入並立即跳過不匹配的輸入。每個匹配和組只包含索引到輸入字符串中的開始和結束字符。字符串僅在調用.Value
時生成。
正則表達式是線程安全的,這意味着一個Regex對象可以存儲在一個靜態字段中,並可以從多個線程中重用。這有助於Web應用程序,因爲不需要爲每個請求創建新的Regex對象
由於這兩個優點,正則表達式被廣泛用於解析日誌文件和提取特定字段。與分割相比,性能可以提高10倍或更多,而內存使用率仍然很低。分割可能很容易導致內存使用量大於原始輸入文件的倍數倍。
它可以走得更快嗎?
是的。正則表達式生成的分析代碼可能不盡可能高效。手寫解析器可能會更快。在這種特殊情況下,如果檢測到$
直到第一個$
,我們要開始捕獲文本。這可以通過以下方法來完成:
IEnumerable<string> GetNames(string input)
{
var builder=new StringBuilder(20);
bool started=false;
foreach(var c in input)
{
if (started)
{
if (c!='$')
{
builder.Append(c);
}
else
{
started=false;
var value=builder.ToString();
yield return value;
builder.Clear();
}
}
else if (c=='$')
{
started=true;
}
}
}
字符串是一個IEnumerable<char>
,所以我們可以檢查一次一個字符,而不必複製他們。通過使用具有預定容量的單個StringBuilder,我們避免重新分配,至少在找到大於20個字符的密鑰之前。
修改此代碼以提取值雖然不是那麼容易。
下面是做這件事,但肯定不是很優雅。基本上在'$'上分割字符串,並採取每一個其他項目會給你的結果(經過一些額外的修剪不需要的字符)。無論是在一本字典
在這個例子中,我也抓住每一個項目的值,然後把:
var input = "($name$:('George') AND $phonenumer$:('456456') AND $emailaddress$:(\"[email protected]\"))";
var inputParts = input.Replace(" AND ", "")
.Trim(')', '(')
.Split(new[] {'$'}, StringSplitOptions.RemoveEmptyEntries);
var keyValuePairs = new Dictionary<string, string>();
for (int i = 0; i < inputParts.Length - 1; i += 2)
{
var key = inputParts[i];
var value = inputParts[i + 1].Trim('(', ':', ')', '"', '\'', ' ');
keyValuePairs[key] = value;
}
foreach (var kvp in keyValuePairs)
{
Console.WriteLine($"{kvp.Key} = {kvp.Value}");
}
// Wait for input before closing
Console.WriteLine("\nDone!\nPress any key to exit...");
Console.ReadKey();
輸出
這不是提取,這是*解析*。它很簡單,但它可以用正則表達式來執行,例如'@「\ $ \ w + \ $」' –
將字符串拆分爲'$'並在結果可枚舉中將每個奇數出現(即第1,第五等):) – DavidG
@DavidG比正則表達式更慢更復雜。它也會產生很多臨時字符串 –