Find and replace CSV delimiter

AS
Ackshaey Singh
Difficulty Easy
Time Complexity
O(n)
Space Complexity
O(n)
String
Cisco Bloomberg

You're in a Bloomberg phone screen when the interviewer pulls up a shared editor and types out a CSV string. "We have a pipeline that ingests comma-separated data," they explain, "but downstream systems expect a different delimiter. How would you swap it out?" It sounds almost too simple, and that's exactly the point. This problem tests whether you can handle string manipulation cleanly, think about edge cases, and write production-ready code under pressure.

TL;DR

Split the CSV string on commas, then join the resulting segments with the replacement delimiter. In Java, use String.join(replacement, csv.split(",", -1)) where the -1 argument preserves trailing empty strings. This runs in O(n) time and O(n) space. The critical detail is that trailing empty segments must be preserved, or inputs like ",1,2,3,4," will produce incorrect output.

Prefer a different language? Jump to solutions in other languages.

Why This Problem Matters

Delimiter replacement might seem trivial, but it shows up constantly in real engineering work. ETL pipelines, log parsing, data export tools, configuration files - they all deal with delimited strings. Interviewers at companies like Cisco and Bloomberg use this as a quick filter to see if you understand string fundamentals before moving to harder problems. Get this wrong, and the interview is over before it starts.

Understanding the Problem

Let's pin down exactly what we're working with:

Given: A comma-separated string and a replacement string Task: Replace every comma with the replacement string Return: The transformed string

replaceCsvDelimiter("a,b,c", "_") -> "a_b_c"

Simple enough. But what about these?

replaceCsvDelimiter(",1,2,3,4,", ",")   -> ",1,2,3,4,"   (no change)
replaceCsvDelimiter(",,,", "")           -> ""             (commas removed)
replaceCsvDelimiter("a,b,c", "_____")    -> "a_____b_____c"
replaceCsvDelimiter("", "|")             -> ""             (empty input)

The replacement string can be anything: a single character, a multi-character string, or even an empty string. The input can start or end with commas, meaning there are empty segments that need to be preserved.

Edge Cases to Consider

  1. Empty input string: Return an empty string
  2. No commas: Return the original string unchanged
  3. Leading/trailing commas: These create empty segments that must survive the transformation
  4. Consecutive commas: Each comma is a delimiter, so ",,," has four empty segments
  5. Replacement equals the original delimiter: The string should be unchanged
  6. Multi-character replacement: The output can be longer than the input

Solution Approach

There are two natural ways to think about this problem.

Approach 1: Split and Join. Break the string apart at every comma, then glue the pieces back together with the new delimiter. This is the idiomatic approach in most languages and handles multi-character replacements naturally.

Approach 2: Character-by-character. Walk through each character, replacing commas as you go. This works fine when the replacement is a single character, but gets awkward with multi-character replacements because you're building the result one piece at a time.

Split-join is cleaner, more readable, and what interviewers expect. Let's go with that.

The Split-Join Pattern

Here's what happens when we split ",1,2,3,4," on commas:

Input:  ",1,2,3,4,"
Split:  ["", "1", "2", "3", "4", ""]

Notice the empty strings at the start and end. Those represent the content before the first comma and after the last comma. If we join these segments with any delimiter, we get a correctly transformed string.

There's one important catch in Java. By default, String.split(",") discards trailing empty strings. That means splitting ",1,2,3,4," would give us ["", "1", "2", "3", "4"], missing the trailing empty segment. Passing -1 as the limit parameter fixes this: csv.split(",", -1) preserves all segments.

Implementation

public class Solution {
  public String replaceCsvDelimiter(String csv, String replacement) {
    // Split on commas, -1 preserves trailing empty strings
    // Join segments with the replacement delimiter
    return String.join(replacement, csv.split(",", -1));
  }
}

That's it. One line of actual logic. Let's trace through a few examples to make sure it holds up.

Example 1: replaceCsvDelimiter("a,b,c", "|")

  • Split "a,b,c" on , with limit -1: ["a", "b", "c"]
  • Join with "|": "a|b|c"

Example 2: replaceCsvDelimiter(",1,2,3,4,", ",")

  • Split ",1,2,3,4," on , with limit -1: ["", "1", "2", "3", "4", ""]
  • Join with ",": ",1,2,3,4," (unchanged, as expected)

Example 3: replaceCsvDelimiter(",,,", "")

  • Split ",,," on , with limit -1: ["", "", "", ""]
  • Join with "": ""

All edge cases handled correctly.

Complexity Analysis

Time Complexity: O(n)

The split operation scans the entire string once to find all commas, producing an array of segments. The join operation then concatenates those segments with the replacement delimiter, which is also linear in the total output size. The combined work is proportional to the length of the input string.

Space Complexity: O(n)

The split operation creates an array of string segments. In the worst case (no commas), this is a single-element array holding the entire string. In another extreme (all commas), the array holds n+1 empty strings. The join operation also produces a new string. Either way, the space usage is linear.

Common Pitfalls

  1. Forgetting the -1 limit in Java. This is the most common mistake. Without it, "a,b," splits into ["a", "b"] instead of ["a", "b", ""]. The trailing empty string disappears, and your output is wrong for any input ending with a comma.

  2. Using regex-based replacement without escaping. If you reach for String.replaceAll(), remember it takes a regex pattern. Special characters in the replacement string (like $ or \) will cause unexpected behavior. Split-join avoids this entirely.

  3. Building strings with concatenation in a loop. If you go the character-by-character route, using += on strings in Java creates a new String object every iteration. Use StringBuilder instead, or just stick with split-join.

Interview Tips

When you see this problem in an interview:

  1. Clarify the constraints first. Ask about empty strings, multi-character replacements, and whether trailing/leading delimiters matter. This shows you think about edge cases before coding.

  2. Mention the split limit parameter. Calling out the -1 in split(",", -1) demonstrates that you know the language's standard library well. Interviewers notice this.

  3. Talk about alternatives. Briefly mention that you could do character-by-character replacement but that split-join is cleaner and handles multi-character replacements. This shows engineering judgment.

  4. Test with edge cases. Walk through ",1,2,3,4," and ",,," to verify your solution handles leading/trailing commas and consecutive delimiters.

Key Takeaways

  • Split-join is the idiomatic pattern for delimiter replacement across virtually every language. It handles single-character and multi-character replacements uniformly.
  • In Java, always pass -1 to split() when you need to preserve trailing empty strings. This is one of those language quirks that separates experienced Java developers from beginners.
  • The problem runs in O(n) time and O(n) space, which is optimal since you must read every character and produce a new string.
  • Edge cases around empty segments (leading commas, trailing commas, consecutive commas) are where most candidates slip up. Testing with ",1,2,3,4," catches the majority of bugs.

Practice Makes Perfect

String manipulation problems like this one build the foundation for more complex interview challenges. Once you're comfortable with delimiter replacement, try these related problems:

  • Reverse words in a string
  • Validate and parse IP addresses
  • Implement a basic CSV parser that handles quoted fields

This problem and hundreds of others are available on Firecode, where over 50,000 developers have prepared for technical interviews at top companies. Consistent daily practice is what separates candidates who get offers from those who don't.

Solutions in Other Languages

Python

Python's approach uses a list comprehension to replace each comma character individually:

class Solution:
    def replace_csv_delimiter(self, csv: str, delimiter: str) -> str:
        return "".join([delimiter if c == "," else c for c in csv])

JavaScript

replaceCsvDelimiter(csv, delimiter) {
  return csv.split(",").join(delimiter);
}

TypeScript

replaceCsvDelimiter(csv: string, delimiter: string): string {
  return csv.split(",").join(delimiter);
}

C++

std::string replaceCsvDelimiter(const std::string &csv,
                                const std::string &replacement) {
  std::string result;
  std::istringstream stream(csv);
  std::string token;
  bool first = true;
  while (std::getline(stream, token, ',')) {
    if (!first) result += replacement;
    result += token;
    first = false;
  }
  if (!csv.empty() && csv.back() == ',') {
    result += replacement;
  }
  return result;
}

Go

func (s *Solution) ReplaceCsvDelimiter(csv string, replacement string) string {
  tokens := strings.Split(csv, ",")
  return strings.Join(tokens, replacement)
}

Scala

Scala maps over each character, replacing commas with the delimiter string:

def replaceCsvDelimiter(csv: String, delimiter: String): String = {
  csv.map { c =>
    if (c == ',') delimiter else c.toString
  }.mkString("")
}

Kotlin

fun replaceCsvDelimiter(csv: String, replacement: String): String {
  return csv.split(",", limit = -1).joinToString(replacement)
}

Swift

func replaceCsvDelimiter(_ csv: String, _ replacement: String) -> String {
  return csv.components(separatedBy: ",").joined(separator: replacement)
}

Ruby

def replace_csv_delimiter(csv, replacement)
  csv.split(",", -1).join(replacement)
end

Rust

pub fn replace_csv_delimiter(&self, csv: String, replacement: String) -> String {
  let parts: Vec<&str> = csv.split(",").collect();
  parts.join(&replacement)
}

C#

public string replaceCsvDelimiter(string csv, string replacement) {
  return string.Join(replacement, csv.Split(','));
}

Dart

String replaceCsvDelimiter(String csv, String replacement) {
  return csv.split(',').join(replacement);
}

PHP

public function replaceCsvDelimiter(string $csv, string $replacement): string {
  return implode($replacement, explode(',', $csv));
}

Frequently Asked Questions

What is the time complexity of replacing delimiters in a CSV string?
The time complexity is O(n) where n is the length of the input string. Both the split and join operations traverse the entire string once, making the overall operation linear in the size of the input.
Why use split and join instead of character-by-character replacement?
Split and join handles multi-character replacements correctly and produces cleaner code. Character-by-character replacement works when the replacement is a single character, but fails when you need to replace a comma with a multi-character string like a pipe-and-space delimiter.
How do you preserve trailing empty strings when splitting in Java?
Pass -1 as the second argument to String.split(). By default, Java's split() discards trailing empty strings. For example, splitting ',1,2,' on commas without -1 gives ['', '1', '2'] instead of the correct ['', '1', '2', ''].
What happens when the replacement string is empty?
When the replacement string is empty, all commas are effectively removed and the remaining segments are concatenated. For example, replacing commas in 'a,b,c' with an empty string produces 'abc'.
Is this problem the same as String.replace() or String.replaceAll()?
Functionally similar, but interviewers typically want you to demonstrate understanding of split/join mechanics rather than calling a single built-in method. The split-join approach also avoids regex pitfalls since replaceAll() uses regex patterns where special characters need escaping.
How does this problem differ across programming languages?
The core split-join pattern is nearly identical across languages. Java uses String.join() and split() with a -1 limit, Python uses join() on a list comprehension or split/join, and JavaScript uses split().join(). The main gotcha is trailing empty string preservation, which varies by language.