如何確定 CSV 檔案中的分隔符
一、簡介
在 CSV(逗號分隔值)檔案中,分隔符號分隔資料字段,並且它們在不同檔案中可能有所不同。常見的分隔符號包括逗號、分號或製表符。處理 CSV 檔案時,識別正確的分隔符號至關重要,因為它可以確保準確解析並防止資料損壞。
在本教程中,我們將探討如何確定 CSV 檔案中的分隔符號。
2. 了解 CSV 檔案中的分隔符
CSV 檔案中的分隔符號分隔記錄中的各個欄位。最常見的分隔符號是:
- 逗號 (
,
) :大多數 CSV 檔案中的標準逗號 - 分號 (
;
) :通常用在以逗號為小數點分隔符號的語言環境中 - 製表符 (
\t
) :通常出現在製表符分隔值檔案中 - 管道 (
|
) :偶爾用於避免與更傳統的分隔符號發生衝突
在處理 CSV 檔案時,我們必須使用正確的分隔符號來正確解析資料。
例如,假設我們有一個包含以下內容的 CSV 檔案:
Location,Latitude,Longitude,Elevation(m)
New York,40.7128,-74.0060,10
Los Angeles,34.0522,-118.2437,71
我們可以看到逗號( ,
)用於分隔欄位。
3. 簡單的線路取樣
確定分隔符號的一種方法是從檔案中取樣幾行並計算常見分隔符號字元的出現次數。
首先,讓我們定義將在多行中測試的可能分隔符號:
private static final char[] POSSIBLE_DELIMITERS = {',', ';', '\t', '|'};
我們可以假設跨行出現最頻繁的字元可能是分隔符號:
@Test
public void givenCSVLines_whenDetectingDelimiterUsingFrequencyCount_thenCorrectDelimiterFound() {
char[] POSSIBLE_DELIMITERS = {',', ';', '\t', '|'};
Map<Character, Integer> delimiterCounts = new HashMap<>();
for (char delimiter : POSSIBLE_DELIMITERS) {
int count = 0;
for (String line : lines) {
count += line.length() - line.replace(String.valueOf(delimiter), "").length();
}
delimiterCounts.put(delimiter, count);
}
char detectedDelimiter = delimiterCounts.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse(',');
assertEquals(',', detectedDelimiter);
}
在這個方法中,我們使用replace()
從行中刪除分隔符, length()
的差異計算每個分隔符號出現的次數。然後我們將計數儲存在HashMap
中。最後,我們使用stream().max()
找到計數最高的分隔符號並傳回它。如果該方法找不到分隔符,則使用orElse()
方法預設為逗號。
4. 使用取樣進行動態分隔符號偵測
偵測分隔符號的更可靠方法是取得第一行中所有字元的集合,然後對其他行進行取樣以測試哪個字元始終導致相同的列數:
@Test
public void givenCSVLines_whenDetectingDelimiter_thenCorrectDelimiterFound() {
String[] lines = {
"Location,Latitude,Longitude,Elevation(m)",
"New York,40.7128,-74.0060,10",
"Los Angeles,34.0522,-118.2437,71",
"Chicago,41.8781,-87.6298,181"
};
char detectedDelimiter = ',';
for (char delimiter : lines[0].toCharArray()) {
boolean allRowsHaveEqualColumnCounts = Arrays.stream(lines)
.map(line -> line.split(Pattern.quote(String.valueOf(delimiter))))
.map(columns -> columns.length)
.distinct()
.count() == 1;
if (allRowsHaveEqualColumnCounts) {
detectedDelimiter = delimiter;
break;
}
}
assertEquals(',', detectedDelimiter);
}
在這種方法中,我們迭代第一行中的每個字符,並將每個字符視為潛在的分隔符。然後我們檢查該字元是否在所有行中產生一致數量的列。此方法使用split()
分割每一行,並使用Pattern.quote()
來處理特殊字符,例如|
或\t
。
對於每個潛在的分隔符,我們使用它來分割所有行併計算每行的列(字段)數。此外,演算法的關鍵部分是透過使用distinct()
檢查列計數是否均勻來驗證所有行中的列數是否保持一致。
最後,如果所考慮的分隔符號為每行產生一致的列數,我們假設它是正確的分隔符號。如果在各行中找不到一致的分隔符,我們也會預設使用逗號。
5. 結論
在本文中,我們探討了兩種偵測 CSV 檔案中分隔符號的方法。第一種方法使用簡單的行採樣併計算潛在分隔符號的出現次數。第二種更強大的方法檢查多行之間的列計數是否一致,以識別正確的分隔符號。根據 CSV 檔案的複雜性,可以應用任一方法。
與往常一樣,本文的完整程式碼範例可以在 GitHub 上找到。