set: how to list not strings starting with

2019-01-29 10:25发布

for example we have in our set:

 bin/obj/Debug/CloudServerPrototype/ra.write.1.tlog 
 bin/obj/Debug/CloudServerPrototype/rc.write.1.tlog 
 bin/obj/Debug/vc100.idb 
 bin/obj/Debug/vc100.pdb 

So this is what I tried based on this grate answer:

#include <iostream>
#include <algorithm>
#include <set>
#include <string>
#include <iterator>

using namespace std;

struct get_pertinent_part
{
    const std::string given_string;

    get_pertinent_part(const std::string& s)
        :given_string(s)
    {
    }

    std::string operator()(const std::string& s)
    {
        std::string::size_type first = 0;

        if (s.find(given_string) == 0)
        {
            first = given_string.length() + 1;
        }

        std::string::size_type count = std::string::npos;
        std::string::size_type pos = s.find_last_of("/");
        if (pos != std::string::npos && pos > first)
        {
            count = pos + 1 - first;
        }

        return s.substr(first, count);
    }
};

void directory_listning_without_directories_demo()
{
    set<string> output;
    set<string> demo_set;

    demo_set.insert("file1");
    demo_set.insert("file2");
    demo_set.insert("folder/file1");
    demo_set.insert("folder/file2");
    demo_set.insert("folder/folder/file1");
    demo_set.insert("folder/folder/file2");
    demo_set.insert("bin/obj/Debug/CloudServerPrototype/ra.write.1.tlog");
    demo_set.insert("bin/obj/Debug/CloudServerPrototype/rc.write.1.tlog");
    demo_set.insert("bin/obj/Debug/vc100.idb");
    demo_set.insert("bin/obj/Debug/vc100.pdb");


    std::transform(demo_set.begin(),
        demo_set.end(),
        std::inserter(output, output.end()),
        get_pertinent_part("bin/obj/Debug/"));

    std::copy(output.begin(),
        output.end(),
        std::ostream_iterator<std::string>(std::cout, "\n"));
}

int main()
{
    directory_listning_without_directories_demo();
    cin.get();
    return 0;
}

This outputs:

CloudServerPrototype/
file1
file2
folder/
folder/folder/
vc100.idb
vc100.pdb

and we are given with bin/obj/Debug/string. We want to cout:

vc100.idb 
vc100.pdb 
CloudServerPrototype/

How to do such thing?

3条回答
唯我独甜
2楼-- · 2019-01-29 10:58

Quick example of what you want to do.

String.find(): http://www.cplusplus.com/reference/string/string/find/

String.subStr(): http://www.cplusplus.com/reference/string/string/substr/

string str = "bin/obj/Debug/vc100.pdb";
    string checkString ("bin/obj/Debug");

     // Check if string starts with the check string
     if (str.find(checkString) == 0){
      // Check if last letter if a "/"
      if(str.substr(str.length()-1,1) == "/"){
        // Output strating at the end of the check string and for
        // the differnce in the strings.
        cout << str.substr(checkString.length(), (str.length() - checkString.length()) ) << endl;
      }
     }
查看更多
混吃等死
3楼-- · 2019-01-29 11:01

It's not clear with which part of the problem you are stuck, so here is a starter for you.

To get the parts of the strings between "given string" and the final '/' (where present):

std::string get_pertinent_part(const std::string& s)
{
    std::string::size_type first = 0;
    if (s.find(given_string) == 0)
    {
        first = given_string.length() + 1;
    }

    std::string::size_type count = std::string::npos;
    std::string::size_type pos = s.find_last_of("/");
    if (pos != std::string::npos && pos > first)
    {
        count = pos + 1 - first;
    }

    return s.substr(first, count);
}

To insert these parts into a new set (output) to guarantee uniqueness you can use the following:

std::transform(your_set.begin(),
               your_set.end(),
               std::inserter(output, output.end()),
               get_pertinent_part);

You may wish to pass given_string into get_pertinent_part(), in which case you'll need to convert it to a functor:

struct get_pertinent_part
{
    const std::string given_string;

    get_pertinent_part(const std::string& s)
        :given_string(s)
    {
    }

    std::string operator()(const std::string& s)
    {
        std::string::size_type first = 0;

        //
        // ...same code as before...
        //

        return s.substr(first, count);
    }
};

You can then call it this way:

std::transform(your_set.begin(),
               your_set.end(),
               std::inserter(output, output.end()),
               get_pertinent_part("bin/obj/Debug"));

To output the new set:

std::copy(output.begin(),
          output.end(),
          std::ostream_iterator<std::string>(std::cout, "\n"));

Sorting the results is left as an exercise.

查看更多
Juvenile、少年°
4楼-- · 2019-01-29 11:20

The easiest way I can think of, using the standard C functions, would be:

char * string1 = "bin/obj/Debug"
char * string2 = "bin/obj/Debug/CloudServerPrototype/rc.write.1.tlog"
char result[64];
// the above code is just to bring the strings into this example

char * position = strstr(string1, string2);
int substringLength;
if(position != NULL){
    position += strlen(string2);
    substringLength = strchr(position, '/') - position;
    strncpy(result, position, substringLength);
}else{
    strcpy(result, string1); // this case is for when your first string is not found
}

cout << result;

The first thing that occurs, is finding the substring, string1, in the string we are analyzing, being string2. Once we found the starting point, and assuming it was there at all, we add the length of that substring to that starting point using pointer arithmatic, and then find the resulting string's length by subtracting the starting position from the ending position, which is found with strchr(position, '/'). Then we simply copy that substring into a buffer and it's there to print with cout.

I am sure there is a fancy way of doing this with std::string, but I'll leave that to anyone who can better explain c++ strings, I never did manage to get comfortable with them, haha

查看更多
登录 后发表回答