Coming Soon
This lesson is currently being developed
std::string_view (part 2)
Learn to work with text strings using the standard library.
What to Expect
Comprehensive explanations with practical examples
Interactive coding exercises to practice concepts
Knowledge quiz to test your understanding
Step-by-step guidance for beginners
Development Status
Content is being carefully crafted to provide the best learning experience
Preview
Early Preview Content
This content is still being developed and may change before publication.
5.9 — std::string_view (part 2)
In this lesson, you'll explore advanced std::string_view
techniques, learn best practices for using it with iterators and algorithms, and understand how to convert between string_view
and std::string
effectively.
Advanced string_view operations
Working with iterators
std::string_view
supports iterators, making it compatible with STL algorithms:
#include <iostream>
#include <string_view>
#include <algorithm>
int main()
{
std::string_view text = "Programming";
std::cout << "Original text: " << text << std::endl;
// Use iterators to traverse the string_view
std::cout << "Characters using iterators: ";
for (auto it = text.begin(); it != text.end(); ++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
// Reverse iterators
std::cout << "Reverse order: ";
for (auto it = text.rbegin(); it != text.rend(); ++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
// Range-based for loop (uses iterators internally)
std::cout << "Using range-based for: ";
for (char c : text)
{
std::cout << c << " ";
}
std::cout << std::endl;
return 0;
}
Output:
Original text: Programming
Characters using iterators: P r o g r a m m i n g
Reverse order: g n i m m a r g o r P
Using range-based for: P r o g r a m m i n g
Using STL algorithms
Since string_view
supports iterators, you can use STL algorithms:
#include <iostream>
#include <string_view>
#include <algorithm>
int main()
{
std::string_view text = "Hello, World! How are you today?";
std::cout << "Text: " << text << std::endl;
// Count occurrences of a character
int space_count = std::count(text.begin(), text.end(), ' ');
int vowel_count = std::count_if(text.begin(), text.end(),
[](char c) { return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'; });
std::cout << "Spaces: " << space_count << std::endl;
std::cout << "Lowercase vowels: " << vowel_count << std::endl;
// Find first vowel
auto vowel_it = std::find_if(text.begin(), text.end(),
[](char c) {
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' ||
c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U';
});
if (vowel_it != text.end())
{
size_t pos = std::distance(text.begin(), vowel_it);
std::cout << "First vowel '" << *vowel_it << "' at position: " << pos << std::endl;
}
// Check if all characters are printable
bool all_printable = std::all_of(text.begin(), text.end(),
[](char c) { return c >= 32 && c <= 126; });
std::cout << "All characters printable: " << all_printable << std::endl;
return 0;
}
Output:
Text: Hello, World! How are you today?
Spaces: 5
Lowercase vowels: 8
First vowel 'e' at position: 1
All characters printable: 1
Converting between string_view and string
Creating std::string from string_view
When you need to modify string data or store it permanently, convert string_view
to std::string
:
#include <iostream>
#include <string_view>
#include <string>
std::string processText(std::string_view input)
{
// Convert string_view to string for modification
std::string result(input); // Create string from string_view
// Now we can modify the string
for (char& c : result)
{
if (c >= 'a' && c <= 'z')
{
c = c - 'a' + 'A'; // Convert to uppercase
}
}
return result;
}
int main()
{
std::string_view original = "Hello, World!";
std::cout << "Original: " << original << std::endl;
std::string processed = processText(original);
std::cout << "Processed: " << processed << std::endl;
// Original string_view is unchanged (it's read-only)
std::cout << "Original unchanged: " << original << std::endl;
return 0;
}
Output:
Original: Hello, World!
Processed: HELLO, WORLD!
Original unchanged: Hello, World!
Using string constructor and assignment
#include <iostream>
#include <string_view>
#include <string>
int main()
{
std::string_view view = "Programming in C++";
// Different ways to create string from string_view
std::string str1(view); // Constructor
std::string str2 = std::string(view); // Explicit constructor
std::string str3;
str3 = view; // Assignment operator
std::cout << "Original view: " << view << std::endl;
std::cout << "String 1: " << str1 << std::endl;
std::cout << "String 2: " << str2 << std::endl;
std::cout << "String 3: " << str3 << std::endl;
// Create string from part of string_view
std::string partial(view.substr(0, 11)); // "Programming"
std::cout << "Partial: " << partial << std::endl;
return 0;
}
Output:
Original view: Programming in C++
String 1: Programming in C++
String 2: Programming in C++
String 3: Programming in C++
Partial: Programming
Practical string processing examples
Text analysis tool
#include <iostream>
#include <string_view>
#include <string>
#include <algorithm>
struct TextAnalysis
{
int characters;
int words;
int sentences;
int vowels;
int consonants;
int digits;
int spaces;
};
TextAnalysis analyzeText(std::string_view text)
{
TextAnalysis analysis = {0, 0, 0, 0, 0, 0, 0};
bool in_word = false;
for (char c : text)
{
analysis.characters++;
// Count spaces
if (c == ' ' || c == '\t' || c == '\n')
{
analysis.spaces++;
in_word = false;
}
// Count sentences (simplified)
else if (c == '.' || c == '!' || c == '?')
{
analysis.sentences++;
in_word = false;
}
// Count vowels and consonants
else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
{
char lower = (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c;
if (lower == 'a' || lower == 'e' || lower == 'i' ||
lower == 'o' || lower == 'u')
{
analysis.vowels++;
}
else
{
analysis.consonants++;
}
if (!in_word)
{
analysis.words++;
in_word = true;
}
}
// Count digits
else if (c >= '0' && c <= '9')
{
analysis.digits++;
if (!in_word)
{
analysis.words++;
in_word = true;
}
}
else
{
in_word = false;
}
}
return analysis;
}
int main()
{
std::string text = "Hello! This is a sample text with 123 numbers. "
"How many words does it contain?";
std::cout << "Text to analyze:" << std::endl;
std::cout << text << std::endl << std::endl;
TextAnalysis analysis = analyzeText(text);
std::cout << "Text Analysis Results:" << std::endl;
std::cout << "=====================" << std::endl;
std::cout << "Characters: " << analysis.characters << std::endl;
std::cout << "Words: " << analysis.words << std::endl;
std::cout << "Sentences: " << analysis.sentences << std::endl;
std::cout << "Vowels: " << analysis.vowels << std::endl;
std::cout << "Consonants: " << analysis.consonants << std::endl;
std::cout << "Digits: " << analysis.digits << std::endl;
std::cout << "Spaces: " << analysis.spaces << std::endl;
return 0;
}
Output:
Text to analyze:
Hello! This is a sample text with 123 numbers. How many words does it contain?
Text Analysis Results:
=====================
Characters: 79
Words: 14
Sentences: 2
Vowels: 21
Consonants: 35
Digits: 3
Spaces: 13
Advanced string parsing
#include <iostream>
#include <string_view>
#include <string>
#include <vector>
class CSVParser
{
public:
static std::vector<std::string_view> parseLine(std::string_view line)
{
std::vector<std::string_view> fields;
size_t start = 0;
bool in_quotes = false;
for (size_t i = 0; i <= line.length(); ++i)
{
char c = (i < line.length()) ? line[i] : '\0';
if (c == '"')
{
in_quotes = !in_quotes;
}
else if ((c == ',' && !in_quotes) || c == '\0')
{
// End of field
std::string_view field = line.substr(start, i - start);
// Remove surrounding quotes if present
if (field.length() >= 2 && field.front() == '"' && field.back() == '"')
{
field = field.substr(1, field.length() - 2);
}
fields.push_back(field);
start = i + 1;
}
}
return fields;
}
static void printFields(const std::vector<std::string_view>& fields)
{
std::cout << "Fields (" << fields.size() << "):" << std::endl;
for (size_t i = 0; i < fields.size(); ++i)
{
std::cout << " " << i + 1 << ": '" << fields[i] << "'" << std::endl;
}
}
};
int main()
{
std::string csv_data =
"Name,Age,City,Salary\n"
"John Doe,30,New York,50000\n"
"Jane Smith,25,\"Los Angeles, CA\",60000\n"
"Bob Johnson,35,Chicago,55000\n";
std::cout << "CSV Data:" << std::endl;
std::cout << csv_data << std::endl;
// Parse each line
std::string_view data_view = csv_data;
size_t line_start = 0;
int line_number = 1;
while (line_start < data_view.length())
{
size_t line_end = data_view.find('\n', line_start);
if (line_end == std::string_view::npos)
line_end = data_view.length();
std::string_view line = data_view.substr(line_start, line_end - line_start);
if (!line.empty())
{
std::cout << "Line " << line_number << ": " << line << std::endl;
auto fields = CSVParser::parseLine(line);
CSVParser::printFields(fields);
std::cout << std::endl;
}
line_start = line_end + 1;
line_number++;
}
return 0;
}
Output:
CSV Data:
Name,Age,City,Salary
John Doe,30,New York,50000
Jane Smith,25,"Los Angeles, CA",60000
Bob Johnson,35,Chicago,55000
Line 1: Name,Age,City,Salary
Fields (4):
1: 'Name'
2: 'Age'
3: 'City'
4: 'Salary'
Line 2: John Doe,30,New York,50000
Fields (4):
1: 'John Doe'
2: '30'
3: 'New York'
4: '50000'
Line 3: Jane Smith,25,"Los Angeles, CA",60000
Fields (4):
1: 'Jane Smith'
2: '25'
3: 'Los Angeles, CA'
4: '60000'
Line 4: Bob Johnson,35,Chicago,55000
Fields (4):
1: 'Bob Johnson'
2: '35'
3: 'Chicago'
4: '55000'
Advanced techniques
String splitting with multiple delimiters
#include <iostream>
#include <string_view>
#include <vector>
#include <algorithm>
std::vector<std::string_view> split(std::string_view text, std::string_view delimiters)
{
std::vector<std::string_view> tokens;
size_t start = 0;
while (start < text.length())
{
// Skip leading delimiters
while (start < text.length() &&
delimiters.find(text[start]) != std::string_view::npos)
{
++start;
}
if (start >= text.length())
break;
// Find end of token
size_t end = start;
while (end < text.length() &&
delimiters.find(text[end]) == std::string_view::npos)
{
++end;
}
// Add token
tokens.push_back(text.substr(start, end - start));
start = end;
}
return tokens;
}
int main()
{
std::string text = "apple,banana;orange:grape|cherry";
std::string_view delimiters = ",;:|";
std::cout << "Text: " << text << std::endl;
std::cout << "Delimiters: " << delimiters << std::endl;
auto tokens = split(text, delimiters);
std::cout << "Tokens (" << tokens.size() << "):" << std::endl;
for (size_t i = 0; i < tokens.size(); ++i)
{
std::cout << " " << i + 1 << ": '" << tokens[i] << "'" << std::endl;
}
return 0;
}
Output:
Text: apple,banana;orange:grape|cherry
Delimiters: ,;:|
Tokens (5):
1: 'apple'
2: 'banana'
3: 'orange'
4: 'grape'
5: 'cherry'
Case-insensitive comparison
#include <iostream>
#include <string_view>
#include <algorithm>
bool iequals(std::string_view lhs, std::string_view rhs)
{
if (lhs.length() != rhs.length())
return false;
return std::equal(lhs.begin(), lhs.end(), rhs.begin(),
[](char a, char b) {
return std::tolower(a) == std::tolower(b);
});
}
bool istarts_with(std::string_view text, std::string_view prefix)
{
if (prefix.length() > text.length())
return false;
return iequals(text.substr(0, prefix.length()), prefix);
}
bool iends_with(std::string_view text, std::string_view suffix)
{
if (suffix.length() > text.length())
return false;
return iequals(text.substr(text.length() - suffix.length()), suffix);
}
int main()
{
std::string_view text = "Programming in C++";
std::cout << "Text: " << text << std::endl;
// Case-insensitive comparisons
std::cout << "Equals 'programming in c++': " << iequals(text, "programming in c++") << std::endl;
std::cout << "Equals 'PROGRAMMING IN C++': " << iequals(text, "PROGRAMMING IN C++") << std::endl;
std::cout << "Equals 'Java Programming': " << iequals(text, "Java Programming") << std::endl;
// Case-insensitive prefix/suffix checks
std::cout << "Starts with 'PROGRAM': " << istarts_with(text, "PROGRAM") << std::endl;
std::cout << "Ends with 'c++': " << iends_with(text, "c++") << std::endl;
std::cout << "Ends with 'java': " << iends_with(text, "java") << std::endl;
return 0;
}
Output:
Text: Programming in C++
Equals 'programming in c++': 1
Equals 'PROGRAMMING IN C++': 1
Equals 'Java Programming': 0
Starts with 'PROGRAM': 1
Ends with 'c++': 1
Ends with 'java': 0
Template functions with string_view
#include <iostream>
#include <string_view>
#include <string>
template<typename Predicate>
int count_if_chars(std::string_view text, Predicate pred)
{
int count = 0;
for (char c : text)
{
if (pred(c))
count++;
}
return count;
}
template<typename Predicate>
std::string filter_chars(std::string_view text, Predicate pred)
{
std::string result;
result.reserve(text.length()); // Optimize: reserve space
for (char c : text)
{
if (pred(c))
result += c;
}
return result;
}
int main()
{
std::string_view text = "Hello123World456!";
std::cout << "Text: " << text << std::endl;
// Count different types of characters
int letters = count_if_chars(text, [](char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
});
int digits = count_if_chars(text, [](char c) {
return c >= '0' && c <= '9';
});
int uppercase = count_if_chars(text, [](char c) {
return c >= 'A' && c <= 'Z';
});
std::cout << "Letters: " << letters << std::endl;
std::cout << "Digits: " << digits << std::endl;
std::cout << "Uppercase: " << uppercase << std::endl;
// Filter characters
std::string only_letters = filter_chars(text, [](char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
});
std::string only_digits = filter_chars(text, [](char c) {
return c >= '0' && c <= '9';
});
std::cout << "Only letters: " << only_letters << std::endl;
std::cout << "Only digits: " << only_digits << std::endl;
return 0;
}
Output:
Text: Hello123World456!
Letters: 10
Digits: 6
Uppercase: 2
Only letters: HelloWorld
Only digits: 123456
Best practices and patterns
Function overloading with string types
#include <iostream>
#include <string_view>
#include <string>
class Logger
{
public:
// Single function that accepts any string-like type
void log(std::string_view message)
{
std::cout << "[LOG] " << message << std::endl;
}
// If you need to store the message, convert to string
void store(std::string_view message)
{
stored_messages.push_back(std::string(message));
}
void showStored() const
{
std::cout << "Stored messages:" << std::endl;
for (const auto& msg : stored_messages)
{
std::cout << " - " << msg << std::endl;
}
}
private:
std::vector<std::string> stored_messages;
};
int main()
{
Logger logger;
// Works with all string types
logger.log("String literal");
std::string str = "std::string object";
logger.log(str);
const char* cstr = "C-style string";
logger.log(cstr);
std::string_view sv = "string_view object";
logger.log(sv);
// Store some messages
logger.store("First stored message");
logger.store(str);
logger.store("Last stored message");
std::cout << std::endl;
logger.showStored();
return 0;
}
Output:
[LOG] String literal
[LOG] std::string object
[LOG] C-style string
[LOG] string_view object
Stored messages:
- First stored message
- std::string object
- Last stored message
Efficient string building
#include <iostream>
#include <string_view>
#include <string>
#include <vector>
// Efficient string joining using string_view
std::string join(const std::vector<std::string_view>& parts, std::string_view separator)
{
if (parts.empty())
return "";
// Calculate total size to avoid multiple reallocations
size_t total_size = 0;
for (const auto& part : parts)
{
total_size += part.length();
}
total_size += (parts.size() - 1) * separator.length();
// Build the result string
std::string result;
result.reserve(total_size);
result += parts[0];
for (size_t i = 1; i < parts.size(); ++i)
{
result += separator;
result += parts[i];
}
return result;
}
int main()
{
std::vector<std::string_view> words = {"Hello", "world", "from", "C++"};
std::cout << "Words to join:" << std::endl;
for (size_t i = 0; i < words.size(); ++i)
{
std::cout << " " << i + 1 << ": '" << words[i] << "'" << std::endl;
}
std::string sentence = join(words, " ");
std::string csv = join(words, ", ");
std::string path = join(words, "/");
std::cout << "\nJoined results:" << std::endl;
std::cout << "Sentence: " << sentence << std::endl;
std::cout << "CSV: " << csv << std::endl;
std::cout << "Path: " << path << std::endl;
return 0;
}
Output:
Words to join:
1: 'Hello'
2: 'world'
3: 'from'
4: 'C++'
Joined results:
Sentence: Hello world from C++
CSV: Hello, world, from, C++
Path: Hello/world/from/C++
Summary
Advanced std::string_view
techniques enable powerful and efficient string processing:
Key Concepts:
- Iterator support: Works with STL algorithms and range-based for loops
- Conversion flexibility: Easy conversion to/from
std::string
when needed - Template compatibility: Works well with generic programming
- Performance benefits: Zero-copy operations for read-only access
Best Practices:
- Use
string_view
for function parameters that read string data - Convert to
std::string
only when modification or permanent storage is needed - Be mindful of lifetime when creating
string_view
from temporary objects - Leverage STL algorithms for complex string processing
- Use reserve() when building strings to improve performance
Common Patterns:
- Parsing and tokenization without copying data
- Case-insensitive operations with custom predicates
- Template functions that work with any string-like type
- Efficient string joining and building techniques
std::string_view
is a powerful tool that, when used correctly, can significantly improve the performance and flexibility of string-handling code while maintaining clean, readable APIs.
Quiz
- Can you use STL algorithms like
std::count
withstd::string_view
? - What's the most efficient way to convert a
string_view
to uppercase? - How do you calculate the total memory needed before building a joined string?
- What's the advantage of using
string_view
as a template parameter type? - When should you convert
string_view
tostd::string
?
Practice exercises
Try these advanced string_view exercises:
- Implement a case-insensitive string find function using
string_view
and STL algorithms - Create a template function that can count occurrences of any substring in any string-like type
- Write a URL parser that extracts components (protocol, host, path, query) using
string_view
- Implement an efficient string replacement function that minimizes memory allocations
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions