Newsgroup: it.comp.lang.c++
Titolo: manipolazione di stringhe

Salve,
dato che sull'help non l'ho trovato, vorrei sapere se esistono routine in
grado di estrarre da una stringa gli ultimi n caratteri o i caratteri dal 3
al 5, ad es.
Io non ho trovato nulla di meglio che invertire la stringa e copiare i primi
n byte con strncpy (e poi reinvertire questi byte), ma spero che ci sia una
funzione già pronta. Se c'è, qual è?
Grazie

 al 5, ad es.
std::string s("sopralapancalacapracampa");
// Estrae gli ultimi n caratteri
int n = 5;
int start = std::max(static_cast<int>(s.size())-n, 0);
std::string s1(s, start, n);
// Estrae i caratteri dal terzo al quinto
std::string s2(s, 2, 3);
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it

funzione già pronta. Se c'è, qual è?
Immagino che tu stia parlando di una stringa C (non std::string
del C++)... purtroppo non esiste una funzione standard che faccia
quello che chiedi ma e' semplice scriverla...
  char *right(const char *src,int n)
  {
    char *t;
    int l=strlen(src);
    // Controllo che non siano stati chiesti troppi
    // caratteri (piu' di quelli che ha la stringa)
    if (n>l) n=l;
    // Alloco spazio per il risultato
    t=new char[n+1]; // malloc(n+1)
    // Invece di invertire la stringa uso l'aritmetica
    // dei puntatori per indirizzare il carattere che
    // mi interessa: in pratica usando src+strlen(src)-n
    // si punta a n caratteri dalla fine della stringa
    // src e a questo punto si puo' usare una semplice
    // chiamata strcpy.
    strcpy(t,src+l-n);
    return t;
  }
  char *mid(const *src,int from,int size)
  {
    char *t;
    int l=strlen(src);
    // Controllo che l'inizio non sia dopo la fine
    // della stringa ed eventualmente aggiusto from
    if (from>l) from=l;
    // Controllo che non siano stati chiesti troppi
    // caratteri ed eventualmente aggiusto size
    if (size>l-from) size=l-from;
    // Alloco lo spazio per il risultato
    t=new char[size+1]; // malloc(size+1)
    // Copio i dati e scrivo il terminatore
    memcpy(t,src+from,size);
    t[size]='\0';
    return t;
  }
La classe std::string possiede metodi standard per estrarre
sottostringhe e ti permette di lavorare *MOLTO* piu'
comodamente che con le stringhe C.
Hai mai pensato di metterti a studiarla ?
HTH
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 int start = std::max(static_cast<int>(s.size())-n, 0);
Una volta si diceva (e si dice ancora) che i cast non andrebbero mai
utilizzati. E' possibile che per fare una cosa banale come la
manipolazione di una stringa ci sia bisogno di un cast?
EMG

manipolazione di una stringa ci sia bisogno di un cast?
Una cosa che odio sono anche quegli unsigned che creano poi problemi
(warning) nei confronti con gli interi (ce ne sono un po' ovunque).
Ma era veramente necessario ? in fondo il range di un unsigned non e'
che sia cosi' terribilmente piu' grande di quello di un int...
Comunque questo e' quello che passa il convento... :(


std::string s1(s, start, n);
purtroppo questa istruzione non è accettata:
string pippo(Edit1->Text,2,3);
could not find a match for
'system::ansistring::ansistring(system::ansistring,int,int)'
Comunque ho risolto con il membro substring della classe ansistring.
Grazie del suggerimento

Hai mai pensato di metterti a studiarla ?
Avrai capito che sono un principiante in c++...
Conoscendo un po' meglio il c, sono abituato a lavorare con gli array di
char, per questo non avevo pensato a usare la classe string (anche perchè
spesso capita di usare funzioni che vogliono un puntatore a char e con le
string devo sempre usare il metodo c_str)
Comunque grazie del suggerimento

La conversione di default e' da int verso unsigned, nel caso di
aritmetica mista.  Se parti da un unsigned e gli sottrai un valore
tale da poter ottenere un risultato negativo, altre strade non ne
vedo...


string devo sempre usare il metodo c_str)
Non sembra essere un cosi grave deterrente...
Luc.

vedo...
Il problema e' proprio questo. Personalmente ritengo la scelta di
fare in modo che size() e alcune altre funzioni che hanno lo stesso
problema ritornino un valore (o accettino parametri) di tipo
unsigned molto discutibile. Obbligano a fare cast assurdi in casi
come quello che hai mostrato e l'allargamento del range non mi
sembra cosi' importante (ad esempio che in una stringa ci si
possano mettere 2Gb o 4Gb caratteri per me non fa poi una gran
differenza: se 32767 caratteri non bastano allora probabilmente
qualche caso in cui te ne servono piu' di 65536 ti capitera' presto).
In quei casi io uso ancora la sintassi di cast del C: passi il
soffrire un po' per queste stranezze, ma prendersi proprio a
martellate sugli alluci no...


 qualche caso in cui te ne servono piu' di 65536 ti capitera' presto).
Nota che da un certo punto di vista e' solo eccesso di zelo da parte del
compilatore, perche' la conversione e' sempre definita: univocamente se
il valore unsigned e' rappresentabile come signed, dipendente
dall'implementazione altrimenti.
Da un punto di vista stilistico sarebbe forse perfino preferibile
invocare localmente il pragma che disabilita il warning
corrispondente...
Ciao,
Nicola

string devo sempre usare il metodo c_str)
già che siamo in argomento, perchè lo standard non prevede una
conversione implicita da std::string a const char*?
Anto

unsigned molto discutibile. Obbligano a fare cast assurdi in casi
la scelta e' dovuta all'uso di size_t. Il quale indica in generale 
il tipo "dimensione". Non distingue, ovviamente, tra una stringa e 
un database! Quindi in generale e' un unsigned con dimensione 
adeguata a coprire l'intero indirizzamento della piattaforma (salvo 
limiti implementativi).
-- 
Posted from 
adsl-21-135.38-151.net24.it
 [151.38.135.21] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 conversione implicita da std::string a const char*?
Perche' restituire un puntatore ad un elemento interno di una struttura
e' una cosa pericolosa e si e' voluto evitare che questo potesse
succedere inavvertitamente. D'altra parte l'alternativa sarebbe stata
allocare dinamicamente una copia della stringa con rischio di memory
leak.
Ciao,
Nicola



Non credo che questo sia il problema. Si sarebbe potuto tornare
esattamente quello che torna c_str() (ovvero un puntatore ad
un'area in formato "C-string" che pero' resta di proprieta'
della stringa).
Un problema che mi viene in mente si sarebbe forse presentato e'
questo:
         void foo(const std::string& s)
         {
           if (s=="YES")
           {
             ...
La riga s=="YES" dovrebbe convertire s in un (const) char ptr
oppure convertire "YES" in std::string ? Entrambe sono
conversioni user-defined ma se venisse presa la prima delle
due strade il confronto potrebbe dare risultati abbastanza
sorprendenti per il programmatore (verrebbero confrontati
gli indirizzi di due aree di memoria). Il compilatore direbbe
che si tratta di una operazione ambigua.
Per risolvere questo problema si dovrebbero implementare
delle versioni overloaded di tutti gli operatori che
interessano std::string in modo da far accettare degli
operandi a destra di tipo const char * (cosa che fra l'altro
ho visto migliora considerevolmente con alcuni compilatori
e prestazioni e snellisce gli eseguibili al costo di un po'
di codice sorgente in piu').
Piu' complicato sarebbe pero' difendersi da sviste come
   std::string s,s2,s3;
   int x;
   if (s==0) { ... }
   // Sintatticamente valido... converte in const char *
   // e confronta con il puntatore nullo
   if (s) { ... }
   // Sintatticamente valido... converte in const char *
   // e confronta implicitamente con il puntatore nullo
   s=s+x;
   // Sintatticamente valido... converte s in const
   // char * e incrementa il puntatore di x posizioni.
   // Quindi costruisce una nuova stringa da questo
   // puntatore incrementato.
   s3=s-s2+s3;
   // Sintatticamente valido... converte s e s2 in
   // const char * e ne fa la differenza come puntatori.
   // Quindi converte s3 in const char *, incrementa questo
   // puntatore della differenza ottenuta e costruisce
   // una nuova stringa da questo puntatore
Forse in fondo chiamare c_str() e' il male minore...


    // una nuova stringa da questo puntatore
Per queste non basterebbe convertire implicitamente a char const *
const?
Ciao,
Nicola

const?
Credo di no per due motivi. Innanzitutto, se ho compreso
correttamente la cosa, sui puntatori intesi come r-value,
(come su tutti i tipi nativi non reference come int, char
o double), non esiste il concetto di "const" (che esiste
invece per gli r-value di tipo istanza di classe).
Quando non ci sono in ballo degli l-value dire "const char
const *" o "const char *" dovrebbe essere la stessa cosa
(const viene comunque "tollerato" per non creare problemi
nella espansione dei template).
Il secondo motivo e' che l'operatore di somma o differenza
non vuole comunque modificare il puntatore ottenuto... ma
semplicemente calcola un nuovo puntatore.
Quando scrivo s=s+x quello che succede e':
 - s viene convertito nel const char const * (che come gia'
   detto "perde" l'attributo const in quanto tipo nativo)
   quando si trasforma in r-value.
 - L'operatore somma ritorna un *altro* puntatore... ottenuto
   sommando al puntatore proveniente da s l'intero x.
   Anche nel caso che invece di esserci un tipo base ci fosse
   stata una classe e un opportuno "operator +" ragionevole
   (ovvero tale da non modificare gli operandi) sarebbe
   comunque stata la stessa cosa.
 - Da questo nuovo puntatore viene costruita una nuova stringa
   e quindi viene chiamato l'operatore di assegnazione per s (la
   seconda costruzione di stringa potrebbe non avvenire... io ho
   trovato notevoli vantaggi di dimensione codice e prestazioni
   nel definire le assegnazioni da const char * in casi
   come questi)
Considera ad esempio il seguente caso...
  class A
  {
    public:
      A operator+(int) const { return A(); }
  };
  int main()
  {
    const A ca;
    A a=ca+1;
    return 0;
  }
... Si tratta di un programma valido in quanto nessuno "tocca"
l'oggetto ca che e' dichiarato essere const.


Quando scrivo s=s+x quello che succede e':
[CUT]
forse č una tecnica un po' complicata, perň si potrebbe fare cosě:
class c_str_ref {
	const char* ptr;
public:
	c_str_ref(char* p): ptr(p) { }
	operator const char* () { return ptr; }
	void operator+(int) { }
};
a questo punto si potrebbe implementare
string::operator c_str_ref() { return c_str(); }
in questo modo non si potrebbe piů fare
string s;
const char* x=s+1;
poichč s+1 restituisce void e non const char*
che ne dite?
Anto
--
Antonio Cuni, 18 anni, studente
Brainbench Certification: 
Master C++: 4.44, higher than 97% of all previous test takers.
Visual Basic 5: 3.06, higher than 77% of all previous test takers.
http://www.brainbench.com/transcript.jsp?pid=1301688