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();  // 等待按键(防止控制台闪退)
    }
}
相关推荐
hssfscv7 小时前
QT的学习笔记4——QMainWindow、资源文件以及主要控件的介绍
笔记·qt·学习
luoyayun3619 小时前
Qt + FFmpeg 音频工具:重采样实现
qt·ffmpeg·重采样
小短腿的代码世界1 天前
Qt Bluetooth源码深度解析:从HCI协议到跨平台API的完整架构
开发语言·qt·架构
小短腿的代码世界1 天前
Qt WebEngine多进程架构与IPC通信:从Chromium多进程到Qt信号槽融合
qt·架构·系统架构
尘中远1 天前
【Qwt 7.0 系列】快速入门与核心新特性概览 —— 更现代的 Qt 数据可视化库
qt·数据可视化·绘图·qwt·科学绘图
初阳7851 天前
【Qt】系统相关(3)——多线程
qt
初阳7851 天前
【Qt】系统相关(2)——文件
开发语言·qt
尘中远2 天前
【Qwt 7.0 系列】坐标轴与刻度系统 —— 刻度引擎、网格、图例与刻度朝内
qt·数据可视化·qcustomplot·qwt·工业软件·科学绘图
sycmancia2 天前
Qt——多线程间的互斥
开发语言·qt
尘中远2 天前
【Qwt 7.0 系列】常用图表类型实战 —— 柱状图、散点图、箱线图与直方图
qt·qwt·工业软件·科学绘图