C# Strings: Build, Clean, Search, and Compare Text
Text processing is a sequence of deliberate choices: preserve meaningful spelling, keep the result of a transformation, check positions, and choose what counts as a match. Learn those choices through small programs you can edit and run.
What you will understand
- Distinguish string literals, char literals and meaningful text identifiers.
- Build messages with escapes, verbatim literals and interpolation.
- Use Length and zero-based indexes without assuming they count visible symbols.
- Retain returned values from Trim, Replace and casing operations.
- Choose ordinal comparison rules explicitly for code and command tokens.
- Search for text and guard a missing separator before extracting.
- Handle null, empty and whitespace-only text according to the field’s rule.
- Build a readable course order card while preserving original display spelling.
Choose string when spelling is the information
A string represents text. That includes a person’s display name, a message and an identifier such as 007. Preserve text when spelling matters. Treating an identifier as a number merely because it contains digits can lose leading zeros and invite meaningless arithmetic.
A char is one UTF-16 code unit, while a string is a sequence of those units. The simple single-letter zone below fits a char, but a name or general symbol sequence belongs in a string. Double quotes create ordinary string literals; single quotes create char literals.
You already know variables, output and the input boundary. This lesson builds on those ideas: construct a message, inspect text, retain transformed results, and choose a comparison rule. Each editor is a separate complete Program.cs. One indexing example intentionally fails so you can inspect an invalid boundary.
Program.cs · Text keeps its spelling
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Member: 007
Zone: B
Name: Mina Ali
The member code is text, so its leading zeros remain meaningful. A string literal uses double quotes; a char literal uses single quotes. This simple zone fits one char, while a name needs a string. Text that looks numeric is not automatically a quantity to calculate with.
Build readable messages with literals and interpolation
Literal syntax determines how source text becomes a string. In an ordinary literal, a backslash starts an escape sequence. For example, \n represents a line feed and \" represents a quote. These characters belong to the source syntax; the output shows their interpreted results.
A verbatim literal starts with @ and treats backslashes literally, which is useful for a Windows-style path. A quote inside it is written twice. Raw string literals are another option for larger blocks, but you do not need additional literal forms to complete this lesson.
Interpolation starts with $ and places expressions inside braces. Use it to combine labels, text values and numeric results clearly. The resulting string is a report of those values at that moment; it does not automatically update later if a source variable changes.
Program.cs · Write quotes, line breaks and a path
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Mina said "Hello".
First line
Second line
C:\lessons\Program.cs
In an ordinary string, backslash introduces escapes such as \" for a quote and \n for a line break. The @ prefix makes this path a verbatim string, so its backslashes are literal. A verbatim string uses doubled quotes to include a quote inside it. This program prints a path; it does not open or create a file.
Program.cs · Build a summary without changing the data
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
C# Basics: 2 copies, total 29.00
Course still: C# Basics
The $ prefix enables interpolation. Each pair of braces contains an expression, and F2 formats the calculated amount with two fractional digits. Building the summary does not change course, quantity or unitPrice. The reference uses the local preview decimal point; output separators can differ with a local terminal’s culture.
Understand Length and check positions before indexing
Length tells you the number of UTF-16 code units in a string. For a simple ASCII code, this matches the familiar count of letters, digits and punctuation. It is a property rather than a method, so write text.Length rather than text.Length().
Positions start at zero. A nonempty string of length six has indexes zero through five. Accessing index six is out of range. Before using Length - 1 to find the last unit, establish that the string is nonempty; an empty string has no first or last unit to access.
This indexing model does not guarantee that one position equals one visible symbol. Emoji and combining marks can occupy multiple units. Avoid slicing arbitrary user text into individual char values when the requirement is to preserve whole displayed characters. The Unicode experiment shows why this distinction matters.
Program.cs · Use zero-based positions
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Length: 6
First: C
Last: 1
Length is a property, so it has no call parentheses. Indexing uses square brackets and starts at zero. For this nonempty ASCII string, the valid indexes are 0 through 5. Length - 1 identifies the last position; Length itself is one position beyond the end.
Program.cs · Inspect an out-of-range index
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Length: 2
Then execution fails with IndexOutOfRangeException.The two valid indexes are 0 and 1. Trying index 2 fails after the length line has printed. A nonempty check is also necessary before using Length - 1, since that expression is -1 for an empty string. A range failure is a logic issue to fix before extracting text.
Program.cs · Length counts UTF-16 code units
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Letter length: 1
Emoji length: 2
Combined spelling length: 2
The emoji occupies two UTF-16 code units. The final string combines e with a separate accent code point, so it also has two code units while it may look like one accented letter. Do not assume Length counts visible symbols or that indexing always returns an entire visible character. Unicode-aware text-element processing is a later topic.
String operations return results; keep the result you need
An existing string’s contents cannot be edited in place. Methods such as Trim and Replace return a result. If you call a method and discard its result, the original variable still refers to its original text. You can assign the returned value to a new variable or back to the existing variable.
Trim removes surrounding whitespace and preserves internal spacing. Replace substitutes matches according to the selected overload; the exact-text overload below is case-sensitive. Neither method guarantees a valid name, a known identifier or safe output in every context.
Keep original data when it helps explain a transformation. A display name should usually preserve its chosen spelling, while a fictional course code may have an explicitly defined uppercase convention. Chaining Trim().ToUpperInvariant() passes one returned value into the next method. That convention is a policy for this code, not a universal identity-normalization algorithm.
Program.cs · Store the result of a text operation
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Ignored result: [ Mina Ali ]
Clean copy: [Mina Ali]
Original: [ Mina Ali ]
Strings are immutable: the existing text is not edited in place. Trim returns the cleaned result, so discarding that result leaves rawName unchanged. The square brackets make surrounding spaces visible. A method may reuse an existing string when nothing changes; the important guarantee is that it does not mutate the original text.
Program.cs · Replace text without rewriting the source
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
C# basics: C# practice
CSharp basics: CSharp practice
This Replace call returns text with each exact occurrence of CSharp replaced. The source spelling and case must match for this overload; it is not a general language-aware rewrite. The draft remains available unchanged. Do not describe a text replacement as validation or sanitization for HTML, SQL or another output context.
Program.cs · Keep display text separate from a code spelling
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Display name: Mina Ali
Canonical code: CS-101
Original code: [ cs-101 ]
The fictional course-code convention uses a trimmed uppercase spelling. Invariant casing avoids depending on the current display culture for this operation. It is not full Unicode normalization and it does not prove that the code exists. Preserve a person’s chosen display spelling; uppercasing a code is not a rule for rewriting every name.
Select equality rules for the meaning of the text
A comparison should state what counts as a match. For the command token START, we choose case-insensitive ordinal matching. That makes start and START equivalent for this exercise without relying on the user’s display culture. It does not make STOP equivalent, and it does not silently remove surrounding spaces.
string.Equals(left, right, StringComparison.OrdinalIgnoreCase) makes that policy explicit. Ordinal compares using a nonlinguistic rule, while OrdinalIgnoreCase applies the corresponding case-insensitive rule. When both operands are strings, == performs case-sensitive ordinal content equality rather than merely checking whether both variables refer to the same object.
Human-language sorting and linguistic searches are different problems and may need a chosen culture. Do not force every comparison through uppercase or lowercase copies. Prefer the overload that expresses the comparison you need, and preserve display spelling separately from a code or command matching policy.
Program.cs · Choose a comparison rule explicitly
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Exact equality: False
Command match: True
Different letters: False
For these string operands, == compares content with case-sensitive ordinal semantics. OrdinalIgnoreCase is an explicit case-insensitive rule for this command token. It does not trim whitespace or ignore arbitrary accents. Human-language sorting and searching can require culture-sensitive rules; choose according to the meaning of the text.
Distinguish finding text from validating a complete format
Contains asks whether a substring is present. StartsWith and EndsWith restrict the match to a boundary. These return bool. IndexOf instead returns the position of the first match, with -1 indicating no match. A match at index zero is successful, so testing greater than zero would miss it.
Once you find a separator, Substring can extract part of the string. Its two-argument form takes a start index and a length, not two endpoint indexes. Guard a missing separator before using that position. Empty pieces can be legitimate extraction results even when the application later rejects them.
A prefix match alone is not complete format validation. CS- starts with CS- even though there is no suffix; CS-ABC also matches the prefix without proving a numeric suffix. Define the full field rule separately. Likewise a substring match does not automatically mean a whole word or a safe file type.
Program.cs · Ask for a match or its first position
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Has token: True
Starts Learn: True
Ends projects: True
Token position: 6
Missing position: -1
Contains, StartsWith and EndsWith answer Boolean questions. IndexOf returns the zero-based start of the first matching token, or -1 when no match is found. Position zero is a successful match, not failure. These are substring operations, so a token match does not establish whole-word matching or validate a complete course code.
Program.cs · Check a search result before extracting
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Prefix: CS
Number text: 101
Substring(0, separator) starts at zero and takes separator code units: its second argument is a length, not an ending index. Substring(separator + 1) takes the rest after the hyphen. The guard prevents using a missing marker. This only splits the first hyphen; the suffix is still text and the program does not enforce a full code pattern.
Handle absence before calling string instance methods
null means no string is present. An empty string contains zero code units. A whitespace-only string contains units but may not be meaningful for a required field. The right policy depends on the field; the required-name example rejects all three.
Use a presence guard before calling Trim, accessing Length or indexing a value that may be null. The guard returns early with useful feedback. The string? annotation communicates possible absence to the compiler; it does not transform or validate a runtime value.
Replacing null with an empty string can be appropriate only when the field’s policy says those states should be equivalent. Do not hide a required missing answer merely to avoid an exception. For fixed exercise values, state the assumptions; for real Console.ReadLine input, carry the checks from the previous input lesson into the text pipeline.
Program.cs · Guard a possibly missing string before using it
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
A display name is required.
null means no string is present; an empty string is present text with length zero; spaces are present but whitespace-only. This guard rejects all three for a required name before calling an instance method. Changing the nullable annotation alone would not make an absent value usable.
Guided repair: cleanup and comparison are separate
The user supplied a command with surrounding spaces and lowercase letters. The intended rule accepts START regardless of case after trimming. The program reports false. Explain why both the cleanup and comparison need repair.
Program.cs · Ignored cleanup and an unsuitable comparison
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Command recognized: False
The result of Trim is discarded, leaving surrounding spaces. The equality test also requires the same case, while this command’s rule is case-insensitive. Fix both causes; changing only one is insufficient for this input.
Repair checkpoints
- Explain why discarding Trim does not change rawCommand.
- Retain a trimmed result without changing the original raw variable.
- Use string.Equals with OrdinalIgnoreCase for the specified command policy.
- START, start and surrounding whitespace should match; STOP must not.
- The empty string and whitespace-only command do not match. Real input still needs a missing-value policy.
Reveal the repair and explanation
Program.cs · Keep the cleaned result and compare deliberately
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Command recognized: True
The cleaned string is stored, then compared with a case-insensitive ordinal command rule. rawCommand is not mutated. This fixed-input repair assumes a present command; a Console.ReadLine answer would first need a missing-value policy like the preceding guard.
Independent lab: a readable course order card
Create a readable course order card from present fixed strings. Preserve the buyer’s chosen case and internal spaces, use a stated uppercase course-code convention, and keep the output calculation separate from text cleanup.
Acceptance checklist
- Trim the buyer name without removing the space between Mina and Ali.
- Trim rawCode and use ToUpperInvariant to produce CS-101.
- Replace CSharp with C# in the draft title and keep the returned title.
- Check the cleaned code for the exact prefix CS- with Ordinal comparison.
- Use interpolation to print all five reference lines, including total 29.00.
- Preserve the original source variables; do not describe a prefix match as full code validation.
- Assume present fixed strings; explain where real input needs presence checks.
Program.cs · Course order card starter
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Buyer: [ Mina Ali ]
Code: [ cs-101 ]
Course: CSharp Basics
Total: 29.00
Has course prefix: False
The total is correct, but all three transformation results are ignored. The code-prefix test uses the raw whitespace-padded lowercase value. Complete the text pipeline and preserve the internal space in the buyer name. A printed order card is a fixed-input exercise, not a saved purchase.
Show hints
- Every transformation returns the text you need to retain.
- Chain cleanup on the returned value, not on an ignored intermediate result.
- Keep the arithmetic inside interpolation numeric; the report is not a saved order.
Reveal the reference solution
Program.cs · Course order card reference solution
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Buyer: [Mina Ali]
Code: [CS-101]
Course: C# Basics
Total: 29.00
Has course prefix: True
Each returned transformation is retained for the next operation or display. The code uses the stated uppercase convention; the name keeps its chosen case and internal spaces. The prefix flag only describes the prefix, not whether a full code is valid or published. The lab assumes present fixed strings; real input needs required-field checks before this pipeline.
Changed-input checks
- Use the name " Noor El Amrani ": keep the internal spaces and case.
- Use code " Cs-205 ": produce CS-205 and a True prefix flag.
- Use code "java-101": produce JAVA-101 and a False prefix flag.
- The code "cs-" has a matching prefix but no suffix; explain why this does not prove a valid course code.
- An empty present name remains empty after Trim. Explain why cleanup alone is not required-field validation.
Recap: follow the text pipeline
Check presence, preserve the original spelling when needed, retain returned transformations, and choose explicit comparison rules. A match or cleaned value does not establish full field validity.
string / char- General text versus one UTF-16 code unit.
$"...{expression}..."- Construct a snapshot message with values and calculated expressions.
text.Length / text[index]- Count or access UTF-16 units; check presence and index boundaries.
Trim / Replace- Return transformed text without mutating the source.
string.Equals(..., StringComparison)- State the equality policy instead of assuming one comparison fits every field.
Contains / StartsWith / EndsWith- Ask whether text matches a location, not whether a full format is valid.
IndexOf / Substring- Find a position, then extract using valid start and length values.
string.IsNullOrWhiteSpace- Check whether a required field is absent, empty or whitespace-only.
Frequently asked questions
Does Trim change my variable?
It returns the trimmed result without mutating the original string. Store that return value in a variable, including the same variable if replacing its value is what you intend.
Does Length count what readers see as characters?
It counts UTF-16 code units. Some visible symbols occupy multiple units or multiple code points. A char index is not a general visible-character selector.
Is Substring’s second argument an ending position?
No. In Substring(start, length), the second argument is the number of code units to take. The one-argument form takes the rest from its start position.
Should I uppercase both strings before every comparison?
Prefer an explicit comparison overload such as OrdinalIgnoreCase when that matches the field rule. Transforming display text is a separate choice. Human-language comparisons can require culture-sensitive rules.
Is null the same as an empty string?
No. null is absence; an empty string is present text with length zero. A required-field rule may reject both, but that policy does not make the states identical.
Does checking CS- at the beginning validate a course code?
No. It only checks the prefix. The suffix can still be missing or invalid, and the code may not refer to a published course. Validate the complete field rule separately.
Can you explain the text operation?
Reason about immutable strings, valid positions, Unicode units and explicit comparisons. Read each explanation after checking your answers.
Next step and references
Strings preserve text, and text operations return results without mutating the original. Keep those results, handle absence, check positions and choose a comparison policy that matches the field. Do not confuse cleanup or a partial match with complete validation.
Next is C# Booleans and Business Rules. You will name conditions clearly, combine requirements, and test the boundaries of a complete decision.
Official references
Original SovranCode explanations, examples and exercises. Technical details were checked against these references.
- Microsoft Learn: Strings and string literals
- Microsoft Learn: String comparison practices
- Microsoft Learn: Character encoding in .NET
Last updated: .