Coming Soon

This lesson is currently being developed

std::string_view (part 2)

Learn to work with text strings using the standard library.

Constants and Strings
Chapter
Beginner
Difficulty
35min
Estimated Time

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

In Progress

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

  1. Can you use STL algorithms like std::count with std::string_view?
  2. What's the most efficient way to convert a string_view to uppercase?
  3. How do you calculate the total memory needed before building a joined string?
  4. What's the advantage of using string_view as a template parameter type?
  5. When should you convert string_view to std::string?

Practice exercises

Try these advanced string_view exercises:

  1. Implement a case-insensitive string find function using string_view and STL algorithms
  2. Create a template function that can count occurrences of any substring in any string-like type
  3. Write a URL parser that extracts components (protocol, host, path, query) using string_view
  4. Implement an efficient string replacement function that minimizes memory allocations

Continue Learning

Explore other available lessons while this one is being prepared.

View Course

Explore More Courses

Discover other available courses while this lesson is being prepared.

Browse Courses

Lesson Discussion

Share your thoughts and questions

💬

No comments yet. Be the first to share your thoughts!

Sign in to join the discussion