2010-08-20 30 views
6

NẾU một chuỗi có thể bao gồm một số yếu tố không cần thiết, ví dụ: @, #, $,%.phân tích chuỗi

Cách tìm chúng và xóa chúng?

Tôi biết điều này yêu cầu lặp lại vòng lặp, nhưng tôi không biết cách biểu diễn sth như @, #, $,%.

Nếu bạn có thể cho tôi một ví dụ về mã, thì tôi sẽ thực sự được đánh giá cao.

+0

Vì bạn đang nói về một chuỗi, tôi sẽ giả sử bạn có nghĩa là C++, và sẽ gắn lại thẻ cho nó như vậy. – James

+2

Một chuỗi có nghĩa là cùng một điều trong C là tốt. –

+2

@ James: Tôi thực sự không nghĩ rằng bạn có thể đưa ra giả định đó. – Vicky

Trả lời

13

Trường hợp phổ biến tiêu chuẩn C sẽ là erase/remove idiom:

#include <string> 
#include <algorithm> 
#include <iostream> 
struct OneOf { 
     std::string chars; 
     OneOf(const std::string& s) : chars(s) {} 
     bool operator()(char c) const { 
       return chars.find_first_of(c) != std::string::npos; 
     } 
}; 
int main() 
{ 
    std::string s = "string with @, #, $, %"; 
    s.erase(remove_if(s.begin(), s.end(), OneOf("@#$%")), s.end()); 
    std::cout << s << '\n'; 
} 

và có, thúc đẩy cung cấp một số cách gọn gàng để viết nó ngắn hơn, ví dụ như sử dụng boost::erase_all_regex

#include <string> 
#include <iostream> 
#include <boost/algorithm/string/regex.hpp> 
int main() 
{ 
    std::string s = "string with @, #, $, %"; 
    erase_all_regex(s, boost::regex("[@#$%]")); 
    std::cout << s << '\n'; 
} 
+1

+1 cho STL và rubenvb

3

Nếu bạn muốn nhận được ưa thích, có Boost.Regex nếu không bạn có thể sử dụng chức năng STL replace kết hợp với chức năng strchr ..

-1

Một nhân vật được thể hiện trong C/C++ bởi dấu nháy đơn, ví dụ '@', '#', v.v ... (ngoại trừ một số ít cần phải thoát).

Để tìm kiếm một ký tự trong một chuỗi, hãy sử dụng strchr(). Dưới đây là một liên kết đến một mẫu mã:

http://www.cplusplus.com/reference/clibrary/cstring/strchr/

+0

C/C++ không phải là ngôn ngữ và chúng cũng không giống nhau. – rubenvb

+0

Một giải pháp hoạt động trong C, hoạt động (thường) trong C++. Điều ngược lại không đúng. Câu trả lời tôi cung cấp cho thấy một giải pháp ** di động ** trên C * và * C++. Xin vui lòng tránh pettiness khi ý nghĩa của những gì được viết là rõ ràng. –

2

là C này hoặc C++? (Bạn đã gắn thẻ cả hai cách.)

Trong C thuần túy, bạn phải lặp lại ký tự theo ký tự và xóa các ký tự không mong muốn. Ví dụ:

char *buf; 
int len = strlen(buf); 
int i, j; 

for (i = 0; i < len; i++) 
{ 
    if (buf[i] == '@' || buf[i] == '#' || buf[i] == '$' /* etc */) 
    { 
     for (j = i; j < len; j++) 
     { 
      buf[j] = buf[j+1]; 
     } 
     i --; 
    } 
} 

Điều này không hiệu quả - nó sẽ kiểm tra từng nhân vật lần lượt và xáo trộn tất cả lên nếu có thứ bạn không muốn. Bạn phải giảm chỉ mục sau đó để đảm bảo bạn kiểm tra ký tự tiếp theo mới.

3

Và nếu bạn vì một lý do, phải tự mình làm C-phong cách, một cái gì đó như thế này sẽ làm việc:

char* oldstr = ... something something dark side ... 

int oldstrlen = strlen(oldstr)+1; 
char* newstr = new char[oldstrlen]; // allocate memory for the new nicer string 
char* p = newstr; // get a pointer to the beginning of the new string 

for (int i=0; i<oldstrlen; i++) // iterate over the original string 
    if (oldstr[i] != '@' && oldstr[i] != '#' && etc....) // check that the current character is not a bad one 
     *p++ = oldstr[i]; // append it to the new string 
*p = 0; // dont forget the null-termination 
2

thuật toán chung:

  1. Xây dựng một chuỗi có chứa các ký tự bạn muốn bị xóa: "@ # $%"
  2. Lặp lại ký tự theo ký tự trên chuỗi chủ đề.
  3. Tìm kiếm nếu mỗi ký tự được tìm thấy trong bộ lọc.
  4. Nếu một nhân vật phù hợp, hãy loại bỏ nó.
  5. Nếu một ký tự không khớp, hãy nối nó vào một chuỗi kết quả.

Tùy thuộc vào thư viện chuỗi bạn đang sử dụng, có các hàm/phương pháp thực hiện một hoặc nhiều bước trên, chẳng hạn như strchr() hoặc find() để xác định xem ký tự có nằm trong chuỗi hay không.

1

sử dụng toán tử bộ ký tự, tức là a sẽ là 'a'. bạn đã không nói cho dù bạn sử dụng các chuỗi C++ (trong trường hợp này bạn có thể sử dụng các phương thức tìm và thay thế) hoặc chuỗi C trong trường hợp này bạn sẽ sử dụng một cái gì đó như thế này (đây không phải là cách tốt nhất, nhưng nó đơn giản chiều):

void RemoveChar(char* szString, char c) 
{ 
    while(*szString != '\0') 
    { 
     if(*szString == c) 
      memcpy(szString,szString+1,strlen(szString+1)+1); 

     szString++; 
    } 
} 
+0

"Toán tử ký tự?" –

+0

ah, bắt tốt, là điều của nhà điều hành tiền xử lý tiền xử lý của MSVC (# @) – Necrolis

1

bạn có thể sử dụng một vòng lặp và gọi find_last_of (http://www.cplusplus.com/reference/string/string/find_last_of/) nhiều lần để tìm ra nhân vật cuối cùng mà bạn muốn thay thế, thay thế nó với trống, và sau đó tiếp tục làm việc về phía sau trong chuỗi.++ cách tiếp cận

1

Something như thế này sẽ làm :

bool is_bad(char c) 
{ 
    if(c == '@' || c == '#' || c == '$' || c == '%') 
    return true; 
    else 
    return false; 
} 

int main(int argc, char **argv) 
{ 
    string str = "a #test #@string"; 
    str.erase(std::remove_if(str.begin(), str.end(), is_bad), str.end()); 
} 

Nếu trình biên dịch của bạn su pports lambdas (hoặc nếu bạn có thể sử dụng boost), nó có thể được làm ngắn hơn. Ví dụ sử dụng tăng :: lambda:

string str = "a #test #@string"; 
    str.erase(std::remove_if(str.begin(), str.end(), (_1 == '@' || _1 == '#' || _1 == '$' || _1 == '%')), str.end()); 

(! Yay hai dòng)

3

Tôi nghĩ cho điều này tôi muốn sử dụng std::remove_copy_if:

#include <string> 
#include <algorithm> 
#include <iostream> 

struct bad_char { 
    bool operator()(char ch) { 
     return ch == '@' || ch == '#' || ch == '$' || ch == '%'; 
    } 
}; 

int main() { 
    std::string in("[email protected]#a$string%[email protected]#stuff$to%ignore"); 
    std::string out; 
    std::remove_copy_if(in.begin(), in.end(), std::back_inserter(out), bad_char()); 
    std::cout << out << "\n"; 
    return 0; 
} 

Kết quả:

Thisisastringwithextrastufftoignore 

Vì dữ liệu chứa các ký tự không mong muốn này thường sẽ xuất phát từ một tệp nào đó, nó cũng đáng xem xét ng loại bỏ chúng khi bạn đọc dữ liệu từ tệp thay vì đọc dữ liệu không mong muốn thành chuỗi và sau đó lọc lọc. Để làm điều này, bạn có thể tạo ra một khía cạnh mà phân loại các ký tự không mong muốn là khoảng trắng:

struct filter: std::ctype<char> 
{ 
    filter(): std::ctype<char>(get_table()) {} 

    static std::ctype_base::mask const* get_table() 
    { 
     static std::vector<std::ctype_base::mask> 
      rc(std::ctype<char>::table_size,std::ctype_base::mask()); 

     rc['@'] = std::ctype_base::space; 
     rc['#'] = std::ctype_base::space; 
     rc['$'] = std::ctype_base::space; 
     rc['%'] = std::ctype_base::space; 
     return &rc[0]; 
    } 
}; 

Để sử dụng, bạn thấm nhuần dòng đầu vào với một miền địa phương sử dụng khía cạnh này, và sau đó đọc bình thường. Đối với thời điểm này tôi sẽ sử dụng một istringstream, mặc dù bạn thường muốn sử dụng một cái gì đó giống như một istream hoặc ifstream:

int main() { 
    std::istringstream in("[email protected]#a$string%[email protected]#stuff$to%ignore"); 
    in.imbue(std::locale(std::locale(), new filter)); 

    std::copy(std::istream_iterator<char>(in), 
     std::istream_iterator<char>(), 
     std::ostream_iterator<char>(std::cout)); 

    return 0; 
} 
+0

Ví dụ của bạn đang làm cho các khía cạnh ít đáng sợ hơn .. từ từ. – Cubbi