Defeated by basic_istringstream

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Keith MacDonald

    Defeated by basic_istringstream

    I've been trying to write generic procedures for persistence of the contents
    of a standard collection. The output side works perfectly, but the input
    side fails when the collection is of strings and a string contains
    whitespace. The problem is that I don't know the type that's stored in the
    collection, so can't treat strings as a special case. This is how I've
    tried to solve the problem:

    template <class COLL>
    void readCollection( COLL& coll)
    {
    COLL::value_typ e elem;

    while (MoreData()) {
    std::basic_istr ingstream<char> (GetData()) >> elem;
    coll.insert(col l.end(), elem);
    }
    }

    Asuming GetData() returns a string from somewhere, this can be successfully
    invoked as:

    std::vector<int > v1;
    readCollection< std::vector<int > >(v1);

    However, the following only works if GetData() returns a string without
    embedded whitespace:

    std::vector<std ::string> v2;
    readCollection< std::vector<std ::string> >(v2);

    Otherwise, each element only gets the first word of each string. Clearly,
    this is a case for unformatted input, but that will only work for strings.
    How can I implement a generic solution?

    Thanks,
    Keith MacDonald


  • John Harrison

    #2
    Re: Defeated by basic_istringst ream


    "Keith MacDonald" <nospam@parasit es.com> wrote in message
    news:4029316a$0 $32939$65c69314 @mercury.nildra m.net...[color=blue]
    > I've been trying to write generic procedures for persistence of the[/color]
    contents[color=blue]
    > of a standard collection. The output side works perfectly, but the input
    > side fails when the collection is of strings and a string contains
    > whitespace. The problem is that I don't know the type that's stored in[/color]
    the[color=blue]
    > collection, so can't treat strings as a special case. This is how I've
    > tried to solve the problem:
    >
    > template <class COLL>
    > void readCollection( COLL& coll)
    > {
    > COLL::value_typ e elem;
    >
    > while (MoreData()) {
    > std::basic_istr ingstream<char> (GetData()) >> elem;
    > coll.insert(col l.end(), elem);
    > }
    > }
    >[/color]

    Use template specialisation

    template <class COLL>
    void readCollection( COLL& coll)
    {
    COLL::value_typ e elem;

    while (MoreData()) {
    std::basic_istr ingstream<char> (GetData()) buffer;
    read_element(bu ffer, elem);
    coll.insert(col l.end(), elem);
    }
    }

    // generic version
    template <class ELEM>
    void read_element(st d::basic_istrin gstream<char>& buffer, ELEM& elem)
    {
    buffer >> elem;
    }

    // specialized version for strings
    template <>
    void read_element<st d::string>(std: :basic_istrings tream<char>& buffer,
    std::string& elem)
    {
    // whatever
    }

    john


    Comment

    • Evan Carew

      #3
      Re: Defeated by basic_istringst ream

      -----BEGIN PGP SIGNED MESSAGE-----
      Hash: SHA1

      Keith,

      Right, that's because the input streams use white space as the default
      delimiter on input. There are a number of solutions to this, you could
      change the default delimiter, you could change the white space on the
      way out, or, if your strings don't have "/n"'s at the end, you could add
      one and then use getline on the way in.

      Evan


      -----BEGIN PGP SIGNATURE-----
      Version: GnuPG v1.0.6 (GNU/Linux)
      Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

      iD8DBQFAKT0Loo/Prlj9GScRAhcrAJ 0XiCItK6qtd9DXU FsepB9uTMfSQgCc CRR5
      2oJOcbGK3Pbi5Or g0wPe/qw=
      =kqVv
      -----END PGP SIGNATURE-----

      Comment

      • John Harrison

        #4
        Re: Defeated by basic_istringst ream

        >[color=blue]
        > while (MoreData()) {
        > std::basic_istr ingstream<char> (GetData()) buffer;[/color]

        Sorry should be

        std::basic_istr ingstream<char> buffer(GetData( ));

        of course.

        john


        Comment

        • Keith MacDonald

          #5
          Re: Defeated by basic_istringst ream

          Evan,

          I like the idea of changing the default delimiter, but can't find out how to
          do it. Please will you point me at the relevant documentation.

          Thanks, Keith

          "Evan Carew" <tempcarew@pobo x.com> wrote in message
          news:102iet727f 26b3d@corp.supe rnews.com...[color=blue]
          > -----BEGIN PGP SIGNED MESSAGE-----
          > Hash: SHA1
          >
          > Keith,
          >
          > Right, that's because the input streams use white space as the default
          > delimiter on input. There are a number of solutions to this, you could
          > change the default delimiter, you could change the white space on the
          > way out, or, if your strings don't have "/n"'s at the end, you could add
          > one and then use getline on the way in.
          >
          > Evan
          >
          >
          > -----BEGIN PGP SIGNATURE-----
          > Version: GnuPG v1.0.6 (GNU/Linux)
          > Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
          >
          > iD8DBQFAKT0Loo/Prlj9GScRAhcrAJ 0XiCItK6qtd9DXU FsepB9uTMfSQgCc CRR5
          > 2oJOcbGK3Pbi5Or g0wPe/qw=
          > =kqVv
          > -----END PGP SIGNATURE-----[/color]


          Comment

          • Keith MacDonald

            #6
            Re: Defeated by basic_istringst ream

            John,

            Perfect solution!

            Thanks,
            Keith MacDonald

            "John Harrison" <john_andronicu s@hotmail.com> wrote in message
            news:c0bekb$15c 3ao$1@ID-196037.news.uni-berlin.de...[color=blue][color=green]
            > >
            > > while (MoreData()) {
            > > std::basic_istr ingstream<char> (GetData()) buffer;[/color]
            >
            > Sorry should be
            >
            > std::basic_istr ingstream<char> buffer(GetData( ));
            >
            > of course.
            >
            > john
            >
            >[/color]


            Comment

            • Branimir Maksimovic

              #7
              Re: Defeated by basic_istringst ream

              "Keith MacDonald" <nospam@parasit es.com> wrote in message news:<402a1811$ 0$32939$65c6931 4@mercury.nildr am.net>...[color=blue]
              > Evan,
              >
              > I like the idea of changing the default delimiter, but can't find out how to
              > do it. Please will you point me at the relevant documentation.
              >
              > Thanks, Keith
              >[/color]

              Sorry for jumping in the middle of discussion, but I had
              similar problem years ago and find solution on this group
              too :)

              One of the tricks is to customize ctype facet.
              eg:
              #include <cstring>
              #include <string>
              #include <locale>
              #include <sstream>
              #include <iostream>

              using namespace std;

              class my_ctype: public ctype<char>
              {
              public:
              my_ctype()
              : ctype<char>(my_ table, false) // false means don't delete table
              {
              memcpy(my_table , classic_table() , table_size);

              my_table[';'] = space; // eg if you wan't other delimiter
              my_table[' '] = alpha; // space is now counted as alpha
              }
              private:
              mask my_table[table_size];
              };

              int main()
              {
              const char* buf="ffff;1.14; word1 word2";
              istringstream is(buf);
              is.imbue(locale (locale::classi c(), new my_ctype));
              int i;double d; string s;
              is>>hex>>i>>dec >>d>>s;
              cout<<"i="<<i<< "\nd="<<d<<"\ns ="<<s<<'\n';
              return 0;
              }

              Greetings, Bane.

              Comment

              • Evan Carew

                #8
                Re: Defeated by basic_istringst ream

                -----BEGIN PGP SIGNED MESSAGE-----
                Hash: SHA1

                Keith,

                Let me have a look, I saw this technique mentioned in this news group
                about a week ago. Since this issue comes up regularly for one reason or
                another.

                On a side note, this issue has come across my desk several times too,
                and I usually end up saving some metadata along with the string to
                determine how long it is. That being said, the following code should get
                around the default delimiter... be forewarned tho, any imbedded 0s in
                your serialized string will fool this method:

                const int BUFLEN( ... );
                char buffer[ BUFLEN ];
                cin.get( buffer, BUFLEN, ',' );

                Evan Carew

                Keith MacDonald wrote:[color=blue]
                > Evan,
                >
                > I like the idea of changing the default delimiter, but can't find out[/color]
                how to[color=blue]
                > do it. Please will you point me at the relevant documentation.
                >
                > Thanks, Keith
                >
                > "Evan Carew" <tempcarew@pobo x.com> wrote in message
                > news:102iet727f 26b3d@corp.supe rnews.com...
                >
                > Keith,
                >
                > Right, that's because the input streams use white space as the default
                > delimiter on input. There are a number of solutions to this, you could
                > change the default delimiter, you could change the white space on the
                > way out, or, if your strings don't have "/n"'s at the end, you could add
                > one and then use getline on the way in.
                >
                > Evan
                >
                >[/color]
                -----BEGIN PGP SIGNATURE-----
                Version: GnuPG v1.0.6 (GNU/Linux)
                Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

                iD8DBQFAKp97oo/Prlj9GScRAvJhAJ 4+9pO/4wFI9CSQ9+ttYef F2IF5AACeK9nI
                qu75bBl9rfzhcJv CeZL/hl0=
                =18fy
                -----END PGP SIGNATURE-----

                Comment

                • Evan Carew

                  #9
                  Re: Defeated by basic_istringst ream

                  -----BEGIN PGP SIGNED MESSAGE-----
                  Hash: SHA1

                  Evan Carew wrote:[color=blue]
                  > Keith,
                  >
                  > Let me have a look, I saw this technique mentioned in this news group
                  > about a week ago. Since this issue comes up regularly for one reason or
                  > another.
                  >
                  > On a side note, this issue has come across my desk several times too,
                  > and I usually end up saving some metadata along with the string to
                  > determine how long it is. That being said, the following code should get
                  > around the default delimiter... be forewarned tho, any imbedded 0s in
                  > your serialized string will fool this method:
                  > [snip][/color]

                  Oops, I meant any embedded character which matches your terminator. I
                  suspect this correction was obvious, but just in case...

                  Evan
                  -----BEGIN PGP SIGNATURE-----
                  Version: GnuPG v1.0.6 (GNU/Linux)
                  Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

                  iD8DBQFAKsA4oo/Prlj9GScRAo6HAJ 9getUoVg7Kvac4J xewBn9XptRhjwCf dOG+
                  fRqAtxhaLExngMm 2D8DpBs8=
                  =GQXu
                  -----END PGP SIGNATURE-----

                  Comment

                  • Keith MacDonald

                    #10
                    Re: Defeated by basic_istringst ream

                    Bane,

                    You're always welcome to jump in, with a solution ;-)

                    I suspected that it would involve locales, but couldn't figure out how.
                    After comparing this solution with John Harrison's template specialisation
                    suggestion, I prefer the latter for solving the problem in hand, but now
                    that you've explained how to manipulate locales, I can use that technique to
                    tidy up some other code that's a bit of a hack.

                    Thanks,
                    Keith MacDonald

                    "Branimir Maksimovic" <bmaxa@volomp.c om> wrote in message
                    news:88cdcbb3.0 402111306.496b2 dcb@posting.goo gle.com...[color=blue]
                    > "Keith MacDonald" <nospam@parasit es.com> wrote in message[/color]
                    news:<402a1811$ 0$32939$65c6931 4@mercury.nildr am.net>...[color=blue]
                    >
                    > Sorry for jumping in the middle of discussion, but I had
                    > similar problem years ago and find solution on this group
                    > too :)
                    >
                    > One of the tricks is to customize ctype facet.
                    > eg:
                    > #include <cstring>
                    > #include <string>
                    > #include <locale>
                    > #include <sstream>
                    > #include <iostream>
                    >
                    > using namespace std;
                    >
                    > class my_ctype: public ctype<char>
                    > {
                    > public:
                    > my_ctype()
                    > : ctype<char>(my_ table, false) // false means don't delete table
                    > {
                    > memcpy(my_table , classic_table() , table_size);
                    >
                    > my_table[';'] = space; // eg if you wan't other delimiter
                    > my_table[' '] = alpha; // space is now counted as alpha
                    > }
                    > private:
                    > mask my_table[table_size];
                    > };
                    >
                    > int main()
                    > {
                    > const char* buf="ffff;1.14; word1 word2";
                    > istringstream is(buf);
                    > is.imbue(locale (locale::classi c(), new my_ctype));
                    > int i;double d; string s;
                    > is>>hex>>i>>dec >>d>>s;
                    > cout<<"i="<<i<< "\nd="<<d<<"\ns ="<<s<<'\n';
                    > return 0;
                    > }
                    >
                    > Greetings, Bane.[/color]


                    Comment

                    • Branimir Maksimovic

                      #11
                      Re: Defeated by basic_istringst ream

                      "Keith MacDonald" <nospam@parasit es.com> wrote in message news:<402b622e$ 0$45837$65c6931 4@mercury.nildr am.net>...[color=blue]
                      > Bane,
                      >
                      > You're always welcome to jump in, with a solution ;-)[/color]

                      Thanks.
                      I forgot to correct a bug(just in case):
                      [color=blue][color=green]
                      > > memcpy(my_table , classic_table() , table_size);[/color][/color]

                      that should be
                      memcpy(my_table , classic_table() , table_size * sizeof(mask));
                      [color=blue][color=green]
                      > > Greetings, Bane.[/color][/color]

                      Comment

                      Working...