Leerzeichen löschen



  • Ich habe eine Datei die so aussieht:

    bezeichnung : wert eins
    bezeichnung:wert zwei
    bezeichnung :wert
    

    Die Datei ist unsortiert nicht sauber lesbar, deswegen möchte ich die leerzeichen vor und nach dem Doppelpunkt löschen. Leider bekomme ich immer eine out of range Exception und komme nicht drauf was ich falsch gemacht habe.

    while( true )
        {
            std::size_t pos = line.find( ':' );
    
            if( pos != std::string::npos )
            {
                if( line.at( pos-1 ) == ' ' )
                {
                    line.erase( line.begin() + (pos-1) ); //erase space behind :
                }
                else if( line.at( pos+1 ) == ' ' )
                {
                    line.erase( line.begin() + (pos+1) ); //erase space after :
                }
                else
                {
                    line.insert( pos+1, "\t\t" );
                    break;
                }
            }
            else
            {
                break;
            }
        }
    

    Edit: die Exception wird von line.at() geworfen.



  • pos-1 kann -1 werden genau wie pos+1 zu str.length() werden kann.



  • Nein daran liegt es nicht, die Datei hat immer einen Bezeichner und einen Wert, somit kann pos nicht über length() oder -1 werden. Das habe ich auch schon getestet.

    Edit: Ok, daran ist es wirklich gescheitert vielen dank!


  • Mod

    Generische Version:

    #include <algorithm>
    #include <iterator>
    #include <type_traits>
    
    template< typename BidirectionalIter,
              typename Predicate >
    BidirectionalIter ltrim_around( BidirectionalIter first,
                                    BidirectionalIter last,
                                    BidirectionalIter iter,
                                    Predicate pred )
    {
    	auto b = iter;
    	while (b != first)
    	{
    		--b;
    		if( !pred(*b) )
    		{
    			++b;
    			break;
    		}
    	}
    
    	if( b == iter ) return last; // sonst ist die nächste Zeile UB
    
    	return std::move( iter, last, b );
    }
    
    template< typename BidirectionalIter,
              typename Predicate >
    BidirectionalIter rtrim_around( BidirectionalIter first,
                                    BidirectionalIter last,
                                    BidirectionalIter iter,
                                    Predicate pred )
    {
    	auto f = iter;
    
    	while (++f != last && pred(*f));
    
    	auto insert_iter = ++iter;
    
    	if( f == insert_iter ) return last; // sonst ist die nächste Zeile UB
    
    	return std::move( f, last, insert_iter );
    }
    
    template< typename BidirectionalIter,
              typename Predicate >
    BidirectionalIter trim_around( BidirectionalIter first,
                                   BidirectionalIter last,
                                   BidirectionalIter iter,
                                   Predicate pred )
    {
    	last = rtrim_around(first, last, iter, pred);
    	return ltrim_around(first, last, iter, pred);
    }
    
    #define DEFINE_DEFAULT_TRIMMER( prefix ) \
    template< typename BidirectionalIter,                                                                                                                \
              typename = typename std::enable_if<std::is_convertible<typename std::iterator_traits<BidirectionalIter>::value_type, char>::value>::type > \
    BidirectionalIter prefix##trim_around( BidirectionalIter first,                                                                                      \
                                           BidirectionalIter last,                                                                                       \
                                           BidirectionalIter iter )                                                                                      \
    {                                                                                                                                                    \
    	static auto pred = []( typename std::iterator_traits<BidirectionalIter>::value_type const& i ){ return std::isspace(i); };                     \
    	return prefix##trim_around(first, last, iter, pred);                                                                                           \
    }
    
    DEFINE_DEFAULT_TRIMMER(r)
    DEFINE_DEFAULT_TRIMMER(l)
    DEFINE_DEFAULT_TRIMMER()
    #undef DEFINE_DEFAULT_TRIMMER
    
    #include <string>
    #include <iostream>
    
    int main()
    {
    	using namespace std;
    	for( string str : {":",
    	                   "  :  ",
    	                   "hi : ho",
    	                   "ha:ha"} )
    	{
    		auto iter = trim_around( begin(str), end(str), begin(str) + str.find(':') );
    		str.erase(iter, end(str));
    		cout << str << '\n';
    	}
    }
    


  • Du kannst auch das machen:

    string clean_line = regex_replace( line, regex("\\s+:\\s+"), ":" ); // Musst noch #include <regex> machen.
    


  • @Arcoth: wenn ich sowas sehe, beschleicht mich das Gefühl, dass ich kein C++ kann 😞 👍



  • Was ist mit?

    std::string line = " fdsf sdf sdf     : sdg dfg    dffh";
    
    line = line.erase(std::remove_if(std::begin(line), std::end(line), std::isspace), std::end(line));
    

  • Mod

    @Skym0sh0: Löscht alle Leerzeichen. Der TE will nur die Leerzeichen um den Doppelpunkt löschen.





  • Arcoth schrieb:

    @Skym0sh0: Löscht alle Leerzeichen. Der TE will nur die Leerzeichen um den Doppelpunkt löschen.

    Ah okay, hatte mir den Eingangspost nicht durchgelesen.


Log in to reply