shell通配符字符串匹配

这篇博客探讨了如何在Linux Shell环境下实现通配符'*'的功能,以匹配特定字符串。通过输入通配符字符串和目标字符串,文章展示了如何找到匹配的子串及其起始位置和长度。示例中,对于不同的输入,代码能够正确地输出匹配信息或返回不匹配的结果。文章提到了非递归版本的代码可能较复杂,但递归实现则更为简洁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Linux Shell命令下通配符’‘表示0个或多个字符, 现编写一段代码实现通配符’‘的功能,注意只需要实现’*’, 不用实现其他通配符。

输入描述:
第一行输入通配字符串
第二行输入要匹配查找的字符串

输出描述:
输出所有匹配的字串起始位置和长度,每行一个匹配输出
如果不匹配,则输出 -1 0
如果有多个按照起始位置和长度的正序输出。

输入例子1:
shopee*.com
shopeemobile.com

输出例子1:
0 16
例子说明1:
0 起始位置,16长度

输入例子2:
*.com
shopeemobile.com

输出例子2:
0 16
1 15
2 14
3 13
4 12
5 11
6 10
7 9
8 8
9 7
10 6
11 5
12 4

输入例子3:
o*m
shopeemobile.com

输出例子3:
2 5
2 14
7 9
14 2

#include <iostream>
#include <string>

using namespace std;

//只考虑一个 * 的情况case通过率为77.78%

int main() {
    string pattern;
    string str;
    cin >> pattern >> str;
    int len1 = pattern.length();
    int len2 = str.length();
    int someMatch = false;
    if(pattern[0] == '*') {
        if(pattern.length() > 1) {
            int idx0 = 1;
            char next = pattern[idx0];
            int pos = 0;
            int pos1 = str.find_first_of(next, pos);
            while(pos1 != str.npos) {
                int idx1 = pos1;
                while(idx0 < len1 && idx1 < len2) {
                    if(pattern[idx0] == str[idx1]) {
                        idx0++;
                        idx1++;
                    } else {
                        break;
                    }
                }
                if(idx0 == len1) {
                    someMatch = true;
                    for(; pos <= pos1; pos++) {
                        cout << pos << " " << idx1-pos << endl;
                    }
                }
                idx0 = 1;
                pos1 = str.find_first_of(next, pos1+1);
            }
            
        }
        else { //只有一个 * ,通吃
            //FIX ME
            someMatch = true;
            for(int i = 0; i < len2; i++) {
                for(int j = i; j < len2; j++) {
                    cout << i << " " << j-i+1 << endl;
                }
            }
        }
    } 
    else { //首字母不是 * 
        int i = 0;
        int start = -1;
        for(int j = 0; j < len2; ++j) {
            if(str[j] == pattern[i]) {
                if(start == -1) {
                    start = j;
                    //cout << "find start " << start << endl;
                }
                
                i++;
                //j++;
            }
            else if(pattern[i] == '*') {
                int idx0 = i+1;
                char next = pattern[idx0];

                int pos = start;
                int pos1 = str.find_first_of(next, start);
                if(start == 14) {
                    //cout << "start " << start << ", next " << next << ", pos1 " << pos1 << endl;
                 }
                while(pos1 != str.npos) {
                    int idx1 = pos1;
                    while(idx0 < len1 && idx1 < len2) {
                        if(pattern[idx0] == str[idx1]) {
                            idx0++;
                            idx1++;
                        } 
                        else if(pattern[idx0] == '*') {
                            if(idx0+1 < len1) {
                                next = pattern[idx0+1];
                                pos1 = str.find_first_of(next,idx1);
                                idx0++;
                                idx1 = pos1;
                            }
                            
                        }
                        else {
                            break;
                        }
                    }
                    if(idx0 == len1) {
                        someMatch = true;
                        cout << start << " " << idx1 - start << endl;
                    }
                    idx0 = i+1;
                    pos1 = str.find_first_of(next, pos1+1);
                }
                
                i = 0;
                j = start + 1;
                start = -1;
            }
            
        }
    }
    if(!someMatch) {
        cout << -1 << " " <<  0 << endl;
    }
}

上面非递归版本的代码太繁琐(是可以优化代码的)
但是用递归来解这一题,代码相当简洁

#include <string>
#include <iostream>
#include <set>    //需要使用有序的集合
using namespace std;

set<int> matchedPos;

void ExgrexMatch(string& pattern, int pos1, string& str, int pos2) {
    if(pos1 == pattern.length()) {    //str[j:pos2) 是匹配的
        matchedPos.insert(pos2);
    }
    if(pos2 == str.length()) {    //str结束
        return;
    }
    
    if(pattern[pos1] == str[pos2]) {    //匹配1个
        ExgrexMatch(pattern, pos1+1, str, pos2+1);
    }
    else if(pattern[pos1] == '*') {
        ExgrexMatch(pattern, pos1+1, str, pos2);    //*匹配0个字符
        ExgrexMatch(pattern, pos1+1, str, pos2+1);  //*匹配1个字符
        ExgrexMatch(pattern, pos1, str, pos2+1);    //*匹配多个字符
    }
    else {    // pattern[pos1] != '*' && pattern[pos1] != str[pos2]
        return;    //此路不匹配
    }
}

int main1() {
    string pattern, str;
    cin >> pattern >> str;
    
    int len1 = pattern.length();
    int len2 = str.length();
    bool someMatched = false;
    for(int j = 0; j < len2; j++) {
        if(str[j] == pattern[0] || pattern[0] == '*') {
            ExgrexMatch(pattern, 0, str, j);
            if(!matchedPos.empty()) {
                someMatched = true;
                for(auto pos : matchedPos) {
                    if(pos > j) {    //*匹配0个字符的时候,pos-j为0,
                                     //此时不应输出
                        cout << j << " " << pos - j << endl;
                    }
                }
                matchedPos.clear();    //清除开始下一轮
            }
        }
    }
    if(!someMatched) {
        cout << -1 << " " << 0 << endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值