表頭名稱:用 NameIndex 精確映射同名 CSV 列)
后端數(shù)據(jù)工程【免費(fèi)下載鏈接】CsvHelperLibrary to help reading and writing CSV files項(xiàng)目地址https://gitcode.com/gh_mirrors/cs/CsvHelper點(diǎn)擊查看免費(fèi)下載導(dǎo)讀現(xiàn)實(shí)世界中的 CSV 數(shù)據(jù)并非總是擁有唯一表頭當(dāng)同一列名在首行出現(xiàn)多次例如Name,Name表示 first name 與 last name 兩列時(shí)CsvHelper 默認(rèn)無法區(qū)分它們。本指南圍繞倉庫文檔 mapping-duplicate-names/index.md 講解如何通過名稱索引Name Index解決這一場(chǎng)景你將掌握NameIndex()映射 API、[NameIndex]特性以及背后的GetFieldIndex索引解析原理并能正確處理讀、寫兩側(cè)的同名列映射。什么是名稱索引Name Index核心概念只有一句話名稱索引指的是同名表頭出現(xiàn)的第幾次第 0 次、第 1 次……而不是該列在整個(gè) CSV 中的物理位置。例如下列數(shù)據(jù)Id,Name,Name 1,first,last兩列Name的物理位置分別是索引 1 和索引 2但它們的名稱索引分別是0和1——因?yàn)榈谝粋€(gè)Name是第 0 次出現(xiàn)第二個(gè)Name是第 1 次出現(xiàn)。這是 CsvHelper 判斷同名表頭時(shí)使用的計(jì)數(shù)口徑與列號(hào)無關(guān)。使用 ClassMap 映射同名表頭官方示例通過ClassMapT完成映射。為了讓它能直接運(yùn)行這里補(bǔ)全了缺失的using并修正了原文檔示例中的筆誤{ get set; }缺少分號(hào)、混用 Tab/空格縮進(jìn)using System.Globalization; using System.IO; using CsvHelper; using CsvHelper.Configuration; void Main() { using (var reader new StreamReader(path\\to\\file.csv)) using (var csv new CsvReader(reader, CultureInfo.InvariantCulture)) { csv.Context.RegisterClassMapFooMap(); var records csv.GetRecordsFoo(); } } public class Foo { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } } public sealed class FooMap : ClassMapFoo { public FooMap() { Map(m m.Id); Map(m m.FirstName).Name(Name).NameIndex(0); Map(m m.LastName).Name(Name).NameIndex(1); } }要點(diǎn)拆解Map(m m.FirstName).Name(Name)與Map(m m.LastName).Name(Name)都聲明列名是Name.NameIndex(0)把FirstName綁定到第一次出現(xiàn)的Name列即數(shù)據(jù)行中的first.NameIndex(1)把LastName綁定到第二次出現(xiàn)的Name列即數(shù)據(jù)行中的last。注意Name和NameIndex必須成對(duì)使用才有效NameIndex的意義是在名為X的表頭中取第N個(gè)單獨(dú)使用NameIndex而沒有設(shè)置名稱時(shí)沒有任何定位作用。用 [NameIndex] 特性直接標(biāo)注屬性如果不寫 ClassMap也可以直接在屬性上使用CsvHelper.Configuration.Attributes.NameIndex特性。倉庫測(cè)試 NameIndexTests.cs 提供了等價(jià)寫法using System.Globalization; using System.IO; using System.Linq; using CsvHelper; using CsvHelper.Configuration.Attributes; private class NameIndexClass { public int Id { get; set; } [NameIndex(1)] public string? Name { get; set; } } using (var reader new StringReader(Id,Name,Name\r\n1,one,two\r\n)) using (var csv new CsvReader(reader, CultureInfo.InvariantCulture)) { var records csv.GetRecordsNameIndexClass().ToList(); // records[0].Id 1 // records[0].Name two綁定到第二個(gè) Name 列 }從特性源碼 NameIndexAttribute.cs 可以看到該特性聲明為AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter同時(shí)實(shí)現(xiàn)了IMemberMapper與IParameterMapper并通過ApplyTo把值寫入memberMap.Data.NameIndex/parameterMap.Data.NameIndex。這意味著它不僅能用于屬性和字段也能用于構(gòu)造函數(shù)參數(shù)的映射倉庫中存在對(duì)應(yīng)的NameIndexAttributeTests.cs與NameIndexMapTests.cs測(cè)試用例例如通過參數(shù)映射把一個(gè)同名表頭列注入構(gòu)造函數(shù)參數(shù)。寫入場(chǎng)景同名列頭也能按 NameIndex 輸出NameIndex同樣作用于寫入過程。在 CsvWriterMappingTests.cs 中可以看到一個(gè)多個(gè)屬性映射到同一個(gè)列名的寫入用例private sealed class SameNameMultipleTimesClassMap : ClassMapSameNameMultipleTimesClass { public SameNameMultipleTimesClassMap() { Map(m m.Name1).Name(ColumnName).NameIndex(1); Map(m m.Name2).Name(ColumnName).NameIndex(2); Map(m m.Name3).Name(ColumnName).NameIndex(0); } }注意這里 NameIndex 的取值1、2、0是亂序的這恰好印證了名稱索引是第幾次出現(xiàn)而非寫入順序?qū)懭霑r(shí) CsvHelper 會(huì)按 NameIndex 的排序輸出列最終表頭仍是ColumnName,ColumnName,ColumnName三列且列順序按名稱索引排序。源碼原理GetFieldIndex 如何定位同名表頭閱讀階段最終都由 CsvReader.cs 的GetFieldIndex方法完成解析其核心邏輯如下前置校驗(yàn)如果沒有 header record或尚未調(diào)用ReadHeader()直接拋出ReaderException遍歷候選名稱對(duì)names參數(shù)即Name()指定的一個(gè)或多個(gè)名稱逐個(gè)經(jīng)PrepareHeaderForMatch處理在namedIndexes字典中查找第一個(gè)命中的名稱校驗(yàn)名稱索引存在性if (name null || index namedIndexes[name].Count)說明第index次出現(xiàn)的同名表頭不存在——這是字段缺失當(dāng)非isTryGet且非 optional 時(shí)會(huì)觸發(fā)MissingFieldFound委托回調(diào)見 CsvReader.cs隨后返回-1結(jié)果緩存命中后將nameKey string.Join(_, names) index寫入namedIndexCache避免重復(fù)遍歷。注釋明確指出該緩存對(duì)使用ConvertUsing的映射有顯著加速返回物理列索引return namedIndexes[name][index]——取的是該名稱第index次出現(xiàn)對(duì)應(yīng)的真實(shí)列位置。namedIndexes本質(zhì)上是一個(gè)名稱 → 該名稱所有出現(xiàn)位置的列表的索引表因此同名表頭無論出現(xiàn)幾次都能通過index精確命中某一列。這正是名稱索引計(jì)數(shù)法與物理列號(hào)兩種口徑的最終交匯點(diǎn)映射時(shí)給的是名稱索引解析時(shí)換算回列位置。邊界情況與注意事項(xiàng)索引越界即字段缺失如果 CSV 中Name只出現(xiàn) 1 次而你映射了NameIndex(1)GetFieldIndex會(huì)判定字段缺失并觸發(fā)MissingFieldFound默認(rèn)拋出MissingFieldException??赏ㄟ^配置MissingFieldFound委托自定義處理邏輯參考 Delegates/MissingFieldFound.cs。索引從 0 開始第一個(gè)同名表頭的 NameIndex 是0這與多數(shù)程序語言數(shù)組下標(biāo)習(xí)慣一致但和第 1 列的人類直覺不同容易踩坑。默認(rèn)索引為 0GetFieldIndex(string name, int index 0, ...)中 index 默認(rèn)為0所以單表頭場(chǎng)景下不寫NameIndex也能取到第一個(gè)匹配列只有出現(xiàn)重復(fù)名稱時(shí)才必須顯式區(qū)分。無表頭記錄時(shí)不可用名稱索引依賴表頭行定位若配置了HasHeaderRecord false無表頭應(yīng)改用Index()按物理列號(hào)映射參見同目錄下的 mapping-by-index 示例。與替代名稱Name(a, b)的關(guān)系Name支持傳入多個(gè)候選名解析時(shí)按聲明順序取第一個(gè)命中的名稱NameIndex作用于最終命中的那個(gè)名稱兩者可以組合使用以實(shí)現(xiàn)多個(gè)別名 同名多次出現(xiàn)的復(fù)雜表頭。小結(jié)處理重復(fù)表頭是 CSV 數(shù)據(jù)清洗中的高頻場(chǎng)景。CsvHelper 通過名稱索引這一計(jì)數(shù)口徑把第 N 次出現(xiàn)的某列從同名表頭中精確分離出來讀側(cè)由GetFieldIndex在namedIndexes索引表中完成換算寫側(cè)按名稱索引排序輸出既可以用ClassMap的.Name().NameIndex()鏈?zhǔn)秸{(diào)用也可以用[NameIndex]特性直標(biāo)屬性還可用于構(gòu)造函數(shù)參數(shù)映射。把握NameIndex 是第幾次出現(xiàn)、而非列位置這一核心語義即可在各種同名表頭的數(shù)據(jù)上寫出清晰、可維護(hù)的映射配置。贊分享后端數(shù)據(jù)工程【免費(fèi)下載鏈接】CsvHelperLibrary to help reading and writing CSV files項(xiàng)目地址https://gitcode.com/gh_mirrors/cs/CsvHelper點(diǎn)擊查看免費(fèi)下載相關(guān)推薦KLayout中數(shù)字開頭的圖層名稱映射問題解析KLayout中數(shù)字開頭的圖層名稱映射問題解析 在使用KLayout進(jìn)行版圖設(shè)計(jì)時(shí)圖層名稱通常以字母開頭但在某些特殊情況下如使用特定工藝設(shè)計(jì)套件PDK時(shí)硬件開發(fā)桌面應(yīng)用圖形學(xué)0168. Excel 表列名稱解析LeetCode 經(jīng)典進(jìn)制轉(zhuǎn)換與字符映射題解0168. Excel 表列名稱解析LeetCode 經(jīng)典進(jìn)制轉(zhuǎn)換與字符映射題解 本篇指南基于「算法通關(guān)手冊(cè)」AlgoNote倉庫中的 0168. Exc教程文檔知識(shí)庫上一篇SLIP線性探針Linear Probe實(shí)戰(zhàn)遷移學(xué)習(xí)性能優(yōu)化的10個(gè)技巧下一篇wiliwili B站客戶端在 Switch 大氣層上怎么裝桌面圖標(biāo)、黑屏、連不上網(wǎng)一次說清創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考