Qt中QString 查找子串的完整指南

文章目录

  • [Qt QString 查找子串的完整指南](#Qt QString 查找子串的完整指南)
    • [1. 基本查找方法](#1. 基本查找方法)
      • [1.1 查找子串是否存在](#1.1 查找子串是否存在)
      • [1.2 查找子串位置](#1.2 查找子串位置)
    • [2. 查找和统计](#2. 查找和统计)
      • [2.1 统计子串出现次数](#2.1 统计子串出现次数)
      • [2.2 查找所有出现位置](#2.2 查找所有出现位置)
    • [3. 高级查找方法](#3. 高级查找方法)
      • [3.1 使用正则表达式查找](#3.1 使用正则表达式查找)
      • [3.2 查找并替换](#3.2 查找并替换)
    • [4. 完整的查找工具类](#4. 完整的查找工具类)
      • [4.1 StringFinder 类](#4.1 StringFinder 类)
    • [5. 实际应用示例](#5. 实际应用示例)
      • [5.1 日志分析工具](#5.1 日志分析工具)
      • [5.2 文本搜索工具](#5.2 文本搜索工具)
    • [6. 性能优化](#6. 性能优化)
      • [6.1 高效查找算法](#6.1 高效查找算法)
    • [7. 完整的示例程序](#7. 完整的示例程序)
    • [8. 重要注意事项](#8. 重要注意事项)

Qt QString 查找子串的完整指南

在 Qt 中,QString 提供了多种查找子串的方法。以下是详细的使用方法和示例:

1. 基本查找方法

1.1 查找子串是否存在

cpp 复制代码
#include <QString>
#include <QDebug>

void basicFindMethods()
{
    QString str = "Hello, World! This is a test string.";
    
    // 1.1 contains() - 检查是否包含子串
    bool containsHello = str.contains("Hello");
    bool containsWorld = str.contains("World");
    bool containsTest = str.contains("test");
    bool containsMissing = str.contains("missing");
    
    qDebug() << "包含 'Hello':" << containsHello;      // true
    qDebug() << "包含 'World':" << containsWorld;      // true
    qDebug() << "包含 'test':" << containsTest;        // true
    qDebug() << "包含 'missing':" << containsMissing;  // false
    
    // 1.2 大小写敏感控制
    bool containsHelloCaseSensitive = str.contains("hello", Qt::CaseSensitive);
    bool containsHelloCaseInsensitive = str.contains("hello", Qt::CaseInsensitive);
    
    qDebug() << "区分大小写查找 'hello':" << containsHelloCaseSensitive;    // false
    qDebug() << "不区分大小写查找 'hello':" << containsHelloCaseInsensitive; // true
    
    // 1.3 使用正则表达式
    bool containsDigits = str.contains(QRegularExpression("\\d+"));
    bool containsWord = str.contains(QRegularExpression("\\btest\\b"));
    
    qDebug() << "包含数字:" << containsDigits;  // false
    qDebug() << "包含完整单词 'test':" << containsWord;  // true
}

1.2 查找子串位置

cpp 复制代码
void findPositions()
{
    QString str = "The quick brown fox jumps over the lazy dog. The fox is brown.";
    
    // 2.1 indexOf() - 查找第一次出现的位置
    int pos1 = str.indexOf("fox");
    int pos2 = str.indexOf("fox", 20);  // 从位置20开始查找
    int pos3 = str.indexOf("cat");      // 未找到返回-1
    
    qDebug() << "'fox' 第一次出现位置:" << pos1;  // 16
    qDebug() << "从位置20开始查找 'fox':" << pos2;  // 44
    qDebug() << "'cat' 的位置:" << pos3;  // -1
    
    // 2.2 lastIndexOf() - 查找最后一次出现的位置
    int lastPos1 = str.lastIndexOf("fox");
    int lastPos2 = str.lastIndexOf("fox", 30);  // 在位置30之前查找
    
    qDebug() << "'fox' 最后一次出现位置:" << lastPos1;  // 44
    qDebug() << "在位置30之前查找 'fox':" << lastPos2;  // 16
    
    // 2.3 大小写敏感控制
    int posCaseSensitive = str.indexOf("The");
    int posCaseInsensitive = str.indexOf("the", 0, Qt::CaseInsensitive);
    
    qDebug() << "区分大小写查找 'The':" << posCaseSensitive;      // 0
    qDebug() << "不区分大小写查找 'the':" << posCaseInsensitive;  // 32
}

2. 查找和统计

2.1 统计子串出现次数

cpp 复制代码
void countOccurrences()
{
    QString str = "apple banana apple orange apple grape apple";
    
    // 3.1 count() - 统计子串出现次数
    int appleCount = str.count("apple");
    int bananaCount = str.count("banana");
    int orangeCount = str.count("orange");
    int missingCount = str.count("pear");
    
    qDebug() << "'apple' 出现次数:" << appleCount;    // 4
    qDebug() << "'banana' 出现次数:" << bananaCount;  // 1
    qDebug() << "'orange' 出现次数:" << orangeCount;  // 1
    qDebug() << "'pear' 出现次数:" << missingCount;   // 0
    
    // 3.2 大小写敏感控制
    int appleCaseSensitive = str.count("Apple", Qt::CaseSensitive);
    int appleCaseInsensitive = str.count("Apple", Qt::CaseInsensitive);
    
    qDebug() << "区分大小写统计 'Apple':" << appleCaseSensitive;    // 0
    qDebug() << "不区分大小写统计 'Apple':" << appleCaseInsensitive; // 4
    
    // 3.3 统计字符出现次数
    int aCount = str.count('a');
    int pCount = str.count('p');
    
    qDebug() << "字符 'a' 出现次数:" << aCount;  // 8
    qDebug() << "字符 'p' 出现次数:" << pCount;  // 8
}

2.2 查找所有出现位置

cpp 复制代码
#include <QVector>

void findAllOccurrences()
{
    QString str = "abracadabra abra kadabra";
    QString sub = "abra";
    
    // 4.1 查找所有出现位置
    QVector<int> positions;
    int pos = 0;
    
    while ((pos = str.indexOf(sub, pos)) != -1) {
        positions.append(pos);
        pos += sub.length();  // 移动到下一个位置
    }
    
    qDebug() << "'abra' 的所有位置:";
    for (int p : positions) {
        qDebug() << "  位置:" << p << ", 子串:" << str.mid(p, sub.length());
    }
    
    // 4.2 查找重叠的子串
    QString str2 = "aaaaa";
    QString sub2 = "aa";
    QVector<int> overlappingPositions;
    
    pos = 0;
    while ((pos = str2.indexOf(sub2, pos)) != -1) {
        overlappingPositions.append(pos);
        pos += 1;  // 只移动1位,允许重叠
    }
    
    qDebug() << "'aa' 在 'aaaaa' 中的所有位置(允许重叠):";
    for (int p : overlappingPositions) {
        qDebug() << "  位置:" << p;
    }
}

3. 高级查找方法

3.1 使用正则表达式查找

cpp 复制代码
#include <QRegularExpression>
#include <QRegularExpressionMatch>

void regexFindMethods()
{
    QString str = "Email: test@example.com, Phone: 123-456-7890, Date: 2023-12-20";
    
    // 5.1 查找匹配
    QRegularExpression emailRegex(R"(\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b)");
    QRegularExpressionMatch emailMatch = emailRegex.match(str);
    
    if (emailMatch.hasMatch()) {
        QString email = emailMatch.captured(0);
        qDebug() << "找到邮箱:" << email;
        qDebug() << "起始位置:" << emailMatch.capturedStart();
        qDebug() << "结束位置:" << emailMatch.capturedEnd();
    }
    
    // 5.2 查找电话号码
    QRegularExpression phoneRegex(R"(\b\d{3}[-.]?\d{3}[-.]?\d{4}\b)");
    QRegularExpressionMatch phoneMatch = phoneRegex.match(str);
    
    if (phoneMatch.hasMatch()) {
        qDebug() << "找到电话:" << phoneMatch.captured(0);
    }
    
    // 5.3 查找所有匹配
    QRegularExpression dateRegex(R"(\b\d{4}-\d{2}-\d{2}\b)");
    QRegularExpressionMatchIterator dateIterator = dateRegex.globalMatch(str);
    
    qDebug() << "所有日期:";
    while (dateIterator.hasNext()) {
        QRegularExpressionMatch match = dateIterator.next();
        qDebug() << "  " << match.captured(0) << "在位置" << match.capturedStart();
    }
    
    // 5.4 捕获组
    QString logLine = "2023-12-20 14:30:25 [INFO] User login successful";
    QRegularExpression logRegex(R"((\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) \[(\w+)\] (.+))");
    QRegularExpressionMatch logMatch = logRegex.match(logLine);
    
    if (logMatch.hasMatch()) {
        qDebug() << "日志解析:";
        qDebug() << "  日期:" << logMatch.captured(1);
        qDebug() << "  时间:" << logMatch.captured(2);
        qDebug() << "  级别:" << logMatch.captured(3);
        qDebug() << "  消息:" << logMatch.captured(4);
    }
}

3.2 查找并替换

cpp 复制代码
void findAndReplace()
{
    QString str = "The quick brown fox jumps over the lazy dog.";
    
    // 6.1 replace() - 简单替换
    QString replaced1 = str;
    replaced1.replace("fox", "cat");
    qDebug() << "替换 'fox' 为 'cat':" << replaced1;
    
    // 6.2 替换所有出现
    QString str2 = "apple apple orange apple";
    QString replaced2 = str2;
    replaced2.replace("apple", "pear");
    qDebug() << "替换所有 'apple' 为 'pear':" << replaced2;
    
    // 6.3 使用正则表达式替换
    QString html = "<p>Hello <b>World</b>!</p>";
    QRegularExpression tagRegex(R"(<[^>]*>)");
    QString textOnly = html;
    textOnly.replace(tagRegex, "");
    qDebug() << "移除HTML标签:" << textOnly;
    
    // 6.4 使用lambda进行复杂替换
    QString numbers = "1, 2, 3, 4, 5";
    QRegularExpression numRegex(R"(\d+)");
    QString doubled = numbers;
    doubled.replace(numRegex, const QRegularExpressionMatch &match {
        int num = match.captured(0).toInt();
        return QString::number(num * 2);
    });
    qDebug() << "数字加倍:" << doubled;
}

4. 完整的查找工具类

4.1 StringFinder 类

cpp 复制代码
// StringFinder.h
#ifndef STRINGFINDER_H
#define STRINGFINDER_H

#include <QString>
#include <QVector>
#include <QRegularExpression>
#include <QPair>

class StringFinder
{
public:
    // 查找单个子串的所有出现
    static QVector<int> findAll(const QString& text, 
                               const QString& substring, 
                               Qt::CaseSensitivity cs = Qt::CaseSensitive);
    
    // 查找多个子串的所有出现
    static QVector<QPair<QString, int>> findAllMultiple(const QString& text, 
                                                       const QStringList& substrings,
                                                       Qt::CaseSensitivity cs = Qt::CaseSensitive);
    
    // 使用正则表达式查找
    static QVector<QRegularExpressionMatch> findAllRegex(const QString& text, 
                                                        const QRegularExpression& regex);
    
    // 统计子串出现次数
    static int countOccurrences(const QString& text, 
                               const QString& substring, 
                               Qt::CaseSensitivity cs = Qt::CaseSensitive);
    
    // 查找最长的公共子串
    static QString findLongestCommonSubstring(const QString& str1, 
                                             const QString& str2);
    
    // 查找最长的重复子串
    static QString findLongestRepeatedSubstring(const QString& text);
    
    // 查找所有单词及其位置
    static QVector<QPair<QString, int>> findAllWords(const QString& text);
    
    // 模糊查找(支持通配符)
    static QVector<int> fuzzyFind(const QString& text, 
                                 const QString& pattern, 
                                 Qt::CaseSensitivity cs = Qt::CaseSensitive);
    
    // 查找并高亮显示
    static QString highlightAll(const QString& text, 
                               const QString& substring, 
                               const QString& startTag = "<mark>",
                               const QString& endTag = "</mark>",
                               Qt::CaseSensitivity cs = Qt::CaseSensitive);
    
private:
    // 计算编辑距离(用于模糊匹配)
    static int editDistance(const QString& s1, const QString& s2);
    
    // 构建后缀数组
    static QVector<int> buildSuffixArray(const QString& text);
};

#endif // STRINGFINDER_H
cpp 复制代码
// StringFinder.cpp
#include "StringFinder.h"
#include <QDebug>
#include <algorithm>

QVector<int> StringFinder::findAll(const QString& text, 
                                  const QString& substring, 
                                  Qt::CaseSensitivity cs)
{
    QVector<int> positions;
    
    if (substring.isEmpty() || text.isEmpty()) {
        return positions;
    }
    
    int pos = 0;
    while ((pos = text.indexOf(substring, pos, cs)) != -1) {
        positions.append(pos);
        pos += substring.length();
    }
    
    return positions;
}

QVector<QPair<QString, int>> StringFinder::findAllMultiple(const QString& text, 
                                                          const QStringList& substrings,
                                                          Qt::CaseSensitivity cs)
{
    QVector<QPair<QString, int>> results;
    
    for (const QString& sub : substrings) {
        QVector<int> positions = findAll(text, sub, cs);
        for (int pos : positions) {
            results.append(qMakePair(sub, pos));
        }
    }
    
    // 按位置排序
    std::sort(results.begin(), results.end(), 
              const QPair<QString, int>& a, const QPair<QString, int>& b {
                  return a.second < b.second;
              });
    
    return results;
}

QVector<QRegularExpressionMatch> StringFinder::findAllRegex(const QString& text, 
                                                           const QRegularExpression& regex)
{
    QVector<QRegularExpressionMatch> matches;
    
    if (!regex.isValid()) {
        qWarning() << "无效的正则表达式:" << regex.errorString();
        return matches;
    }
    
    QRegularExpressionMatchIterator iterator = regex.globalMatch(text);
    while (iterator.hasNext()) {
        matches.append(iterator.next());
    }
    
    return matches;
}

int StringFinder::countOccurrences(const QString& text, 
                                  const QString& substring, 
                                  Qt::CaseSensitivity cs)
{
    if (substring.isEmpty()) {
        return 0;
    }
    
    int count = 0;
    int pos = 0;
    
    while ((pos = text.indexOf(substring, pos, cs)) != -1) {
        count++;
        pos += substring.length();
    }
    
    return count;
}

QString StringFinder::findLongestCommonSubstring(const QString& str1, 
                                                const QString& str2)
{
    int m = str1.length();
    int n = str2.length();
    
    if (m == 0 || n == 0) {
        return QString();
    }
    
    // 创建DP表
    QVector<QVector<int>> dp(m + 1, QVector<int>(n + 1, 0));
    int maxLength = 0;
    int endPos = 0;
    
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (str1[i-1] == str2[j-1]) {
                dp[i][j] = dp[i-1][j-1] + 1;
                if (dp[i][j] > maxLength) {
                    maxLength = dp[i][j];
                    endPos = i;
                }
            }
        }
    }
    
    if (maxLength == 0) {
        return QString();
    }
    
    return str1.mid(endPos - maxLength, maxLength);
}

QString StringFinder::findLongestRepeatedSubstring(const QString& text)
{
    int n = text.length();
    
    if (n < 2) {
        return QString();
    }
    
    // 构建后缀数组
    QVector<int> suffixArray = buildSuffixArray(text);
    
    // 查找最长公共前缀
    QString longest = "";
    
    for (int i = 0; i < n - 1; i++) {
        int idx1 = suffixArray[i];
        int idx2 = suffixArray[i + 1];
        
        // 查找公共前缀
        int k = 0;
        while (idx1 + k < n && idx2 + k < n && 
               text[idx1 + k] == text[idx2 + k]) {
            k++;
        }
        
        if (k > longest.length()) {
            longest = text.mid(idx1, k);
        }
    }
    
    return longest;
}

QVector<QPair<QString, int>> StringFinder::findAllWords(const QString& text)
{
    QVector<QPair<QString, int>> words;
    
    QRegularExpression wordRegex(R"(\b\w+\b)");
    QRegularExpressionMatchIterator iterator = wordRegex.globalMatch(text);
    
    while (iterator.hasNext()) {
        QRegularExpressionMatch match = iterator.next();
        QString word = match.captured(0);
        int pos = match.capturedStart();
        words.append(qMakePair(word, pos));
    }
    
    return words;
}

QVector<int> StringFinder::fuzzyFind(const QString& text, 
                                    const QString& pattern, 
                                    Qt::CaseSensitivity cs)
{
    QVector<int> positions;
    
    if (pattern.isEmpty() || text.isEmpty()) {
        return positions;
    }
    
    QString patternLower = (cs == Qt::CaseInsensitive) ? pattern.toLower() : pattern;
    QString textLower = (cs == Qt::CaseInsensitive) ? text.toLower() : text;
    
    // 简单的模糊匹配:检查是否包含所有字符(按顺序)
    for (int i = 0; i <= text.length() - pattern.length(); i++) {
        bool found = true;
        int patternIndex = 0;
        
        for (int j = i; j < text.length() && patternIndex < pattern.length(); j++) {
            if (textLower[j] == patternLower[patternIndex]) {
                patternIndex++;
            }
        }
        
        if (patternIndex == pattern.length()) {
            positions.append(i);
        }
    }
    
    return positions;
}

QString StringFinder::highlightAll(const QString& text, 
                                  const QString& substring, 
                                  const QString& startTag,
                                  const QString& endTag,
                                  Qt::CaseSensitivity cs)
{
    if (substring.isEmpty()) {
        return text;
    }
    
    QString result = text;
    QVector<int> positions = findAll(text, substring, cs);
    
    // 从后往前插入标签,避免位置偏移
    for (int i = positions.size() - 1; i >= 0; i--) {
        int pos = positions[i];
        result.insert(pos + substring.length(), endTag);
        result.insert(pos, startTag);
    }
    
    return result;
}

int StringFinder::editDistance(const QString& s1, const QString& s2)
{
    int m = s1.length();
    int n = s2.length();
    
    QVector<QVector<int>> dp(m + 1, QVector<int>(n + 1));
    
    for (int i = 0; i <= m; i++) {
        dp[i][0] = i;
    }
    for (int j = 0; j <= n; j++) {
        dp[0][j] = j;
    }
    
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (s1[i-1] == s2[j-1]) {
                dp[i][j] = dp[i-1][j-1];
            } else {
                dp[i][j] = 1 + qMin(qMin(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]);
            }
        }
    }
    
    return dp[m][n];
}

QVector<int> StringFinder::buildSuffixArray(const QString& text)
{
    int n = text.length();
    QVector<int> suffixArray(n);
    
    // 初始化后缀数组
    for (int i = 0; i < n; i++) {
        suffixArray[i] = i;
    }
    
    // 简单排序(对于大文本,应使用更高效的算法)
    std::sort(suffixArray.begin(), suffixArray.end(),
              int a, int b {
                  return text.mid(a) < text.mid(b);
              });
    
    return suffixArray;
}

5. 实际应用示例

5.1 日志分析工具

cpp 复制代码
#include "StringFinder.h"
#include <QFile>
#include <QTextStream>
#include <QDateTime>

class LogAnalyzer
{
public:
    struct LogEntry {
        QDateTime timestamp;
        QString level;
        QString message;
        int lineNumber;
    };
    
    QVector<LogEntry> parseLogFile(const QString& filePath)
    {
        QVector<LogEntry> entries;
        
        QFile file(filePath);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            qWarning() << "无法打开日志文件:" << filePath;
            return entries;
        }
        
        QTextStream in(&file);
        int lineNumber = 0;
        
        // 日志格式: [2023-12-20 14:30:25] [INFO] Message here
        QRegularExpression logRegex(R"(\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(\w+)\] (.+))");
        
        while (!in.atEnd()) {
            QString line = in.readLine();
            lineNumber++;
            
            QRegularExpressionMatch match = logRegex.match(line);
            if (match.hasMatch()) {
                LogEntry entry;
                entry.timestamp = QDateTime::fromString(match.captured(1), "yyyy-MM-dd HH:mm:ss");
                entry.level = match.captured(2);
                entry.message = match.captured(3);
                entry.lineNumber = lineNumber;
                
                entries.append(entry);
            }
        }
        
        file.close();
        return entries;
    }
    
    QVector<LogEntry> searchInLogs(const QVector<LogEntry>& entries, 
                                  const QString& searchTerm,
                                  Qt::CaseSensitivity cs = Qt::CaseInsensitive)
    {
        QVector<LogEntry> results;
        
        for (const LogEntry& entry : entries) {
            if (entry.message.contains(searchTerm, cs) ||
                entry.level.contains(searchTerm, cs)) {
                results.append(entry);
            }
        }
        
        return results;
    }
    
    QVector<LogEntry> searchByRegex(const QVector<LogEntry>& entries,
                                   const QRegularExpression& regex)
    {
        QVector<LogEntry> results;
        
        for (const LogEntry& entry : entries) {
            if (regex.match(entry.message).hasMatch() ||
                regex.match(entry.level).hasMatch()) {
                results.append(entry);
            }
        }
        
        return results;
    }
    
    QMap<QString, int> countByLevel(const QVector<LogEntry>& entries)
    {
        QMap<QString, int> counts;
        
        for (const LogEntry& entry : entries) {
            counts[entry.level]++;
        }
        
        return counts;
    }
};

5.2 文本搜索工具

cpp 复制代码
class TextSearchTool
{
public:
    struct SearchResult {
        int lineNumber;
        int position;
        QString line;
        QString matchedText;
    };
    
    QVector<SearchResult> searchInFile(const QString& filePath, 
                                      const QString& searchTerm,
                                      Qt::CaseSensitivity cs = Qt::CaseSensitive)
    {
        QVector<SearchResult> results;
        
        QFile file(filePath);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            return results;
        }
        
        QTextStream in(&file);
        int lineNumber = 0;
        
        while (!in.atEnd()) {
            QString line = in.readLine();
            lineNumber++;
            
            int pos = 0;
            while ((pos = line.indexOf(searchTerm, pos, cs)) != -1) {
                SearchResult result;
                result.lineNumber = lineNumber;
                result.position = pos;
                result.line = line;
                result.matchedText = searchTerm;
                
                results.append(result);
                
                pos += searchTerm.length();
            }
        }
        
        file.close();
        return results;
    }
    
    QVector<SearchResult> searchWithRegex(const QString& filePath,
                                         const QRegularExpression& regex)
    {
        QVector<SearchResult> results;
        
        QFile file(filePath);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            return results;
        }
        
        QTextStream in(&file);
        int lineNumber = 0;
        
        while (!in.atEnd()) {
            QString line = in.readLine();
            lineNumber++;
            
            QRegularExpressionMatchIterator iterator = regex.globalMatch(line);
            while (iterator.hasNext()) {
                QRegularExpressionMatch match = iterator.next();
                
                SearchResult result;
                result.lineNumber = lineNumber;
                result.position = match.capturedStart();
                result.line = line;
                result.matchedText = match.captured();
                
                results.append(result);
            }
        }
        
        file.close();
        return results;
    }
    
    QString highlightMatches(const QString& text, 
                            const QVector<SearchResult>& results,
                            const QString& startTag = "<span style='background-color: yellow;'>",
                            const QString& endTag = "</span>")
    {
        QString highlighted = text;
        
        // 从后往前插入标签,避免位置偏移
        for (int i = results.size() - 1; i >= 0; i--) {
            const SearchResult& result = results[i];
            highlighted.insert(result.position + result.matchedText.length(), endTag);
            highlighted.insert(result.position, startTag);
        }
        
        return highlighted;
    }
};

6. 性能优化

6.1 高效查找算法

cpp 复制代码
#include <QHash>
#include <QSet>

class EfficientStringSearcher
{
public:
    // Boyer-Moore算法实现
    static QVector<int> boyerMooreSearch(const QString& text, 
                                        const QString& pattern,
                                        Qt::CaseSensitivity cs = Qt::CaseSensitive)
    {
        QVector<int> positions;
        
        int n = text.length();
        int m = pattern.length();
        
        if (m == 0 || n == 0 || m > n) {
            return positions;
        }
        
        // 预处理坏字符表
        QHash<QChar, int> badChar;
        for (int i = 0; i < m - 1; i++) {
            badChar[pattern[i]] = m - 1 - i;
        }
        
        // 搜索
        int s = 0;
        while (s <= n - m) {
            int j = m - 1;
            
            // 从右向左比较
            while (j >= 0) {
                QChar textChar = (cs == Qt::CaseInsensitive) ? 
                                 text[s + j].toLower() : text[s + j];
                QChar patternChar = (cs == Qt::CaseInsensitive) ? 
                                   pattern[j].toLower() : pattern[j];
                
                if (textChar != patternChar) {
                    break;
                }
                j--;
            }
            
            if (j < 0) {
                // 找到匹配
                positions.append(s);
                s += (s + m < n) ? badChar.value(text[s + m], m) : 1;
            } else {
                // 根据坏字符规则移动
                QChar badCharValue = (cs == Qt::CaseInsensitive) ? 
                                    text[s + j].toLower() : text[s + j];
                int shift = badChar.value(badCharValue, m);
                s += qMax(1, shift - (m - 1 - j));
            }
        }
        
        return positions;
    }
    
    // KMP算法实现
    static QVector<int> kmpSearch(const QString& text, 
                                 const QString& pattern,
                                 Qt::CaseSensitivity cs = Qt::CaseSensitive)
    {
        QVector<int> positions;
        
        int n = text.length();
        int m = pattern.length();
        
        if (m == 0 || n == 0 || m > n) {
            return positions;
        }
        
        // 构建部分匹配表
        QVector<int> lps(m, 0);
        int len = 0;
        int i = 1;
        
        while (i < m) {
            QChar c1 = (cs == Qt::CaseInsensitive) ? pattern[i].toLower() : pattern[i];
            QChar c2 = (cs == Qt::CaseInsensitive) ? pattern[len].toLower() : pattern[len];
            
            if (c1 == c2) {
                len++;
                lps[i] = len;
                i++;
            } else {
                if (len != 0) {
                    len = lps[len - 1];
                } else {
                    lps[i] = 0;
                    i++;
                }
            }
        }
        
        // 搜索
        i = 0;  // text的索引
        int j = 0;  // pattern的索引
        
        while (i < n) {
            QChar textChar = (cs == Qt::CaseInsensitive) ? text[i].toLower() : text[i];
            QChar patternChar = (cs == Qt::CaseInsensitive) ? pattern[j].toLower() : pattern[j];
            
            if (textChar == patternChar) {
                i++;
                j++;
            }
            
            if (j == m) {
                // 找到匹配
                positions.append(i - j);
                j = lps[j - 1];
            } else if (i < n && textChar != patternChar) {
                if (j != 0) {
                    j = lps[j - 1];
                } else {
                    i++;
                }
            }
        }
        
        return positions;
    }
    
    // 多模式搜索(Aho-Corasick算法)
    class AhoCorasick
    {
    public:
        struct Node {
            QHash<QChar, int> next;
            int fail = 0;
            QVector<int> output;
        };
        
        AhoCorasick() {
            nodes.append(Node());  // 根节点
        }
        
        void addPattern(const QString& pattern, int patternId) {
            int current = 0;
            
            for (QChar ch : pattern) {
                if (!nodes[current].next.contains(ch)) {
                    nodes[current].next[ch] = nodes.size();
                    nodes.append(Node());
                }
                current = nodes[current].next[ch];
            }
            
            nodes[current].output.append(patternId);
        }
        
        void buildFailureLinks() {
            QQueue<int> queue;
            
            // 第一层的失败链接指向根节点
            for (auto it = nodes[0].next.begin(); it != nodes[0].next.end(); ++it) {
                int nextNode = it.value();
                nodes[nextNode].fail = 0;
                queue.enqueue(nextNode);
            }
            
            while (!queue.isEmpty()) {
                int current = queue.dequeue();
                
                for (auto it = nodes[current].next.begin(); it != nodes[current].next.end(); ++it) {
                    QChar ch = it.key();
                    int child = it.value();
                    
                    int fail = nodes[current].fail;
                    while (fail != 0 && !nodes[fail].next.contains(ch)) {
                        fail = nodes[fail].fail;
                    }
                    
                    if (nodes[fail].next.contains(ch)) {
                        nodes[child].fail = nodes[fail].next[ch];
                    } else {
                        nodes[child].fail = 0;
                    }
                    
                    // 合并输出
                    nodes[child].output.append(nodes[nodes[child].fail].output);
                    
                    queue.enqueue(child);
                }
            }
        }
        
        QHash<int, QVector<int>> search(const QString& text) {
            QHash<int, QVector<int>> results;
            int current = 0;
            
            for (int i = 0; i < text.length(); i++) {
                QChar ch = text[i];
                
                while (current != 0 && !nodes[current].next.contains(ch)) {
                    current = nodes[current].fail;
                }
                
                if (nodes[current].next.contains(ch)) {
                    current = nodes[current].next[ch];
                } else {
                    current = 0;
                }
                
                for (int patternId : nodes[current].output) {
                    results[patternId].append(i);
                }
            }
            
            return results;
        }
        
    private:
        QVector<Node> nodes;
    };
};

7. 完整的示例程序

cpp 复制代码
// main.cpp
#include <QCoreApplication>
#include <QDebug>
#include "StringFinder.h"
#include "EfficientStringSearcher.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    
    qDebug() << "=== QString 查找子串示例 ===";
    
    // 示例1: 基本查找
    {
        qDebug() << "\n1. 基本查找示例:";
        QString text = "The quick brown fox jumps over the lazy dog.";
        
        qDebug() << "文本:" << text;
        qDebug() << "包含 'fox':" << text.contains("fox");
        qDebug() << "'fox' 位置:" << text.indexOf("fox");
        qDebug() << "'the' 最后位置:" << text.lastIndexOf("the");
    }
    
    // 示例2: 使用StringFinder
    {
        qDebug() << "\n2. 使用StringFinder:";
        QString text = "apple banana apple orange apple";
        
        QVector<int> positions = StringFinder::findAll(text, "apple");
        qDebug() << "'apple' 所有位置:" << positions;
        
        int count = StringFinder::countOccurrences(text, "apple");
        qDebug() << "'apple' 出现次数:" << count;
        
        QString highlighted = StringFinder::highlightAll(text, "apple", "[", "]");
        qDebug() << "高亮显示:" << highlighted;
    }
    
    // 示例3: 正则表达式查找
    {
        qDebug() << "\n3. 正则表达式查找:";
        QString text = "Email: test@example.com, Phone: 123-456-7890";
        
        QRegularExpression emailRegex(R"(\b\w+@\w+\.\w+\b)");
        QRegularExpressionMatch match = emailRegex.match(text);
        
        if (match.hasMatch()) {
            qDebug() << "找到邮箱:" << match.captured(0);
        }
        
        QRegularExpression phoneRegex(R"(\d{3}-\d{3}-\d{4})");
        match = phoneRegex.match(text);
        
        if (match.hasMatch()) {
            qDebug() << "找到电话:" << match.captured(0);
        }
    }
    
    // 示例4: 高效算法比较
    {
        qDebug() << "\n4. 高效算法比较:";
        QString text = QString(10000, 'a') + "b" + QString(10000, 'a');
        QString pattern = "aaaab";
        
        // 普通查找
        auto start = std::chrono::high_resolution_clock::now();
        QVector<int> naivePositions = StringFinder::findAll(text, pattern);
        auto end = std::chrono::high_resolution_clock::now();
        auto naiveTime = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        
        // KMP算法
        start = std::chrono::high_resolution_clock::now();
        QVector<int> kmpPositions = EfficientStringSearcher::kmpSearch(text, pattern);
        end = std::chrono::high_resolution_clock::now();
        auto kmpTime = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        
        // Boyer-Moore算法
        start = std::chrono::high_resolution_clock::now();
        QVector<int> bmPositions = EfficientStringSearcher::boyerMooreSearch(text, pattern);
        end = std::chrono::high_resolution_clock::now();
        auto bmTime = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        
        qDebug() << "朴素算法时间:" << naiveTime << "微秒";
        qDebug() << "KMP算法时间:" << kmpTime << "微秒";
        qDebug() << "Boyer-Moore算法时间:" << bmTime << "微秒";
        qDebug() << "找到的位置数量:" << naivePositions.size();
    }
    
    // 示例5: 多模式搜索
    {
        qDebug() << "\n5. 多模式搜索(Aho-Corasick):";
        
        EfficientStringSearcher::AhoCorasick ac;
        
        // 添加模式
        ac.addPattern("he", 0);
        ac.addPattern("she", 1);
        ac.addPattern("his", 2);
        ac.addPattern("hers", 3);
        
        ac.buildFailureLinks();
        
        QString text = "ushers";
        auto results = ac.search(text);
        
        qDebug() << "在 '" << text << "' 中找到的模式:";
        for (auto it = results.begin(); it != results.end(); ++it) {
            QString pattern;
            switch (it.key()) {
            case 0: pattern = "he"; break;
            case 1: pattern = "she"; break;
            case 2: pattern = "his"; break;
            case 3: pattern = "hers"; break;
            }
            
            qDebug() << "  模式 '" << pattern << "' 在位置:" << it.value();
        }
    }
    
    return 0;
}

8. 重要注意事项

  1. 性能考虑

    • 对于小文本,使用简单的 indexOf() 足够
    • 对于大文本或频繁搜索,考虑使用高效算法
    • 避免在循环中重复编译正则表达式
  2. 编码问题

    • 确保文本编码正确
    • 处理多字节字符
    • 注意大小写敏感设置
  3. 内存管理

    • 避免创建不必要的临时字符串
    • 使用引用传递大字符串
    • 及时释放不需要的内存
  4. 错误处理

    • 检查查找结果(-1表示未找到)
    • 验证正则表达式的有效性
    • 处理空字符串和边界情况
  5. 国际化

    • 考虑不同语言的文本处理
    • 处理Unicode字符
    • 注意区域设置

通过上述方法,您可以在Qt中高效地查找和处理子串。根据具体需求选择合适的查找方法和算法。

上一篇:QT设计师里的Text Edit、Plain Text Edit、Text Browser分别用什么作用,又有什么区别


不积跬步,无以至千里。


代码铸就星河,探索永无止境

在这片由逻辑与算法编织的星辰大海中,每一次报错都是宇宙抛来的谜题,每一次调试都是与未知的深度对话。不要因短暂的"运行失败"而止步,因为真正的光芒,往往诞生于反复试错的暗夜。

请铭记

  • 你写下的每一行代码,都在为思维锻造韧性;
  • 你破解的每一个Bug,都在为认知推开新的门扉;
  • 你坚持的每一分钟,都在为未来的飞跃积蓄势能。

技术的疆域没有终点,只有不断刷新的起点。无论是递归般的层层挑战,还是如异步并发的复杂困局,你终将以耐心为栈、以好奇心为指针,遍历所有可能。

向前吧,开发者

让代码成为你攀登的绳索,让逻辑化作照亮迷雾的灯塔。当你在终端看到"Success"的瞬间,便是宇宙对你坚定信念的回响------
此刻的成就,永远只是下一个奇迹的序章! 🚀


(将技术挑战比作宇宙探索,用代码、算法等意象强化身份认同,传递"持续突破"的信念,结尾以动态符号激发行动力。)

cpp 复制代码
//c++ hello world示例
#include <iostream>  // 引入输入输出流库

int main() {
    std::cout << "Hello World!" << std::endl;  // 输出字符串并换行
    return 0;  // 程序正常退出
}

print("Hello World!")  # 调用内置函数输出字符串

package main  // 声明主包
py 复制代码
#python hello world示例
import "fmt"  // 导入格式化I/O库
go 复制代码
//go hello world示例
func main() {
    fmt.Println("Hello World!")  // 输出并换行
}
C# 复制代码
//c# hello world示例
using System;  // 引入System命名空间

class Program {
    static void Main() {
        Console.WriteLine("Hello World!");  // 输出并换行
        Console.ReadKey();  // 等待按键(防止控制台闪退)
    }
}
相关推荐
世转神风-3 小时前
qt-在字符串中指定位置插入字符串
开发语言·qt
hqwest4 小时前
码上通QT实战03--登录逻辑
开发语言·qt·登录·嵌入式实时数据库·界面设计
世转神风-6 小时前
QEventLoop与QTimer联动
qt
SunkingYang7 小时前
QT如何将char*转QString
qt·qstring·指针·转换·char
hqwest9 小时前
码上通QT实战01--创建项目
开发语言·qt·sqlite3·qt项目·qwidget·qwindow
深蓝海拓10 小时前
PySide6从0开始学习的笔记(十二) QProgressBar(进度条)
笔记·python·qt·学习·pyqt
神仙别闹11 小时前
基于 SeetaFace+VS2017+Qt 的人脸识别
开发语言·qt
XXYBMOOO11 小时前
Qt 调用 DLL 实现固件升级进度弹窗(完整实战案例)
开发语言·qt·性能优化·简单工厂模式