亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在沒有 LINQ 的情況下創建在 HTTP (< 2.0) 字符串中找到的標頭的字典查找

在沒有 LINQ 的情況下創建在 HTTP (< 2.0) 字符串中找到的標頭的字典查找

C#
拉風的咖菲貓 2023-05-14 16:09:03
我目前正在從日志文件中解析一些 HTTP 請求標頭,我需要將它們拆分并創建一個字典以便于查找。我正在使用的代碼是:public static Dictionary<string, string> CreateLookupDictionary(string input)    {        Debug.WriteLine(input);        return input.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)            .Select(x => x.Split(new string[] {": "}, StringSplitOptions.None))            .ToDictionary(x => x[0], x => x[1], StringComparer.InvariantCultureIgnoreCase);    }這適用于 99% 的標頭,但隨后.........Keep-Alive: timeout=20Expires: Sat, 04 Jun 2011 18:43:08 GMTCache-Control: max-age=31536000Cache-Control: publicAccept-Ranges: bytes...現在密鑰Cache-Control已經存在,因此它會拋出有關密鑰已存在的異常。有沒有一種優雅的方法來覆蓋那里的價值,除非我真的必須這樣做,否則我不想重寫 LINQ。
查看完整描述

3 回答

?
HUWWW

TA貢獻1874條經驗 獲得超12個贊

  • .ToDictionary要求每一個key都是獨一無二的,通過設計。

  • Linq 沒有.DistinctBy( x => x.y )方法,但我們可以使用.GroupBy( x => x.y ).Select( grp => grp.Last() ). 這具有丟棄具有相同值的所有先前結果的效果y。

因此,如果您首先按 HTTP 標頭名稱分組,然后選擇每個組中的最后一項,那么這將得到您想要的:

// Using cached static fields to avoid unnecessary array allocation:

static readonly String[] _splitOnLines = new String[] { "\r\n" };

static readonly String[] _splitHeader  = new String[] { ": " };


public static Dictionary<String,String> CreateLookupDictionary(String input)

{

    Debug.WriteLine(input);

    return input

        .Split( _splitOnLines , StringSplitOptions.RemoveEmptyEntries )

        .Select( line => line.Split( _splitHeader, StringSplitOptions.None ) )

        .Where( arr => arr.Length == 2 ) // filter out invalid lines, if any

        .Select( arr => ( name: arr[0], value: arr[1] ) ) // using C# 7 named tuples for maintainability

        .GroupBy( header => header.name )

        .Select( duplicateHeaderGroup => duplicateHeaderGroup.Last() )

        .ToDictionary( header => header.name, header.value, StringComparer.InvariantCultureIgnoreCase );

}

或者,使用自定義聚合,該聚合使用始終成功的鍵索引Item設置器屬性。如果與我之前的示例相比很少有重復項,則此方法可能具有更快的性能。


public static Dictionary<String,String> CreateLookupDictionary(String input)

{

    Debug.WriteLine(input);

    return input

        .Split( _splitOnLines , StringSplitOptions.RemoveEmptyEntries )

        .Select( line => line.Split( _splitHeader, StringSplitOptions.None ) )

        .Where( arr => arr.Length == 2 )

        .Select( arr => ( name: arr[0], value: arr[1] ) )

        .Aggregate(

            new Dictionary<String,String>( StringComparer.InvariantCultureIgnoreCase ),

            ( d, header ) =>

            {

                d[ header.name ] = header.value;

                return d;

            }

        );

}


查看完整回答
反對 回復 2023-05-14
?
狐的傳說

TA貢獻1804條經驗 獲得超3個贊

.Net Core 2.0 有解決辦法:

使用 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpParser 類:

如果您使用這種方法,您將能夠處理許多無法預料的邊緣情況。

這是偽代碼(未經測試)——這只適用于 .Net Core(顯然)

using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;

using System;

using System.Buffers;

using System.Collections.Generic;

using System.Text;


public class ExampleUsage?

{

? ? public static void Main(string[] args)

? ? {

? ? ? ? string requestString =

? ? ? ? @"POST /resource/?query_id=0 HTTP/1.1

? ? ? ? Host: example.com

? ? ? ? User-Agent: custom

? ? ? ? Accept: */*

? ? ? ? Connection: close

? ? ? ? Content-Length: 20

? ? ? ? Content-Type: application/json


? ? ? ? {""key1"":1, ""key2"":2}";


? ? ? ? var headerResult = Parser.Parse(requestString);

? ? }

}


public class Parser : IHttpHeadersHandler

{

? ? private Dictionary<string, string> result = null;


? ? public Dictionary<string, string> Parse(string requestString)

? ? {

? ? ? ? result = new Dictionary<string, string>();??


? ? ? ? byte[] requestRaw = Encoding.UTF8.GetBytes(requestString);

? ? ? ? ReadOnlySequence<byte> buffer = new ReadOnlySequence<byte>(requestRaw);

? ? ? ? HttpParser<Program> parser = new HttpParser<Program>();


? ? ? ? parser.ParseRequestLine(this, buffer, out var consumed, out var examined);

? ? ? ? buffer = buffer.Slice(consumed);


? ? ? ? parser.ParseHeaders(this, buffer, out consumed, out examined, out var b);

? ? ? ? buffer = buffer.Slice(consumed);

? ? }


? ? public void OnHeader(Span<byte> name, Span<byte> value)

? ? {

? ? ? ? result.Add(Encoding.UTF8.GetString(name), Encoding.UTF8.GetString(value));

? ? }

}


查看完整回答
反對 回復 2023-05-14
?
慕尼黑8549860

TA貢獻1818條經驗 獲得超11個贊

就我個人而言,我會使用它.ToLookup來保留同一個鍵的多個值。 .ToLookup不會在重復鍵上出錯,它會創建一個IEnumerable<V>值,這種情況是IEnumerable<string>:


public static ILookup<string, string> CreateLookup(string input)

{

    Debug.WriteLine(input);

    return input.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)

        .Select(x => x.Split(new string[] {": "}, StringSplitOptions.None))

        .ToLookup(x => x[0], x => x[1], StringComparer.InvariantCultureIgnoreCase);

}


查看完整回答
反對 回復 2023-05-14
  • 3 回答
  • 0 關注
  • 200 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號