Ändra innehållet i en string (C++)

Permalänk

Ändra innehållet i en string (C++)

Det jag undrar är hur man ändrar värde på innehållet i en sträng enligt en tabell. Säg att a-ö är 1-28 där siffran motsvarar deras plats i alfabetet. Så om de skriver aaaaaa vill jag alltså ersätta det med 1 1 1 1 1 1. Skriver de däremot abcdefghij så vill jag ersätta det med 1 2 3 4 5 6 osv. Värt att tillägga kan vara att abc def ghi = 1 2 3 4 5 6 osv där mellanslag (' ') ersätts med 2 mellanslag.

Det är väl det, just nu, samt hur man skapar egna resursfiler. För jag kan tänka mig att programmet, med ersättningsfunktionen kommer se väldigt plottrigt å fult ut.

Jag har läst på internet, jag har läst i böcker. Hur jag än gör så förstår jag mig inte på det. Böckerna jag lyckats komma över är i ren och skör grekiska för mig. Så om ni skulle vara vänliga och hjälpa mig och samtidigt förklara, med så nybörjarvänlig svenska som möjligt så skulle jag bli fruktansvärt glad.

Mvh

Permalänk
Vila i frid

Använd CString's klassmedlemmar för att manipulera strängen t.ex. CString.GetAt, CString.SetAt och CString.Insert

C++ gratis @ Microsoft Express Downloads - Visual Studio Express and SQL Server Express om du kör Windows.

Permalänk
Hedersmedlem

Enklast är nog att bara titta på varje tecken och bygga upp en ny sträng:

string s = "test abcdåäö"; stringstream ss; for(int i = 0; i < s.size(); ++i) { if(s[i] >= 'a' && s[i] <= 'z') ss << s[i]-'a'+1 << " "; else if(s[i] == ' ') ss << " "; else if(s[i] == -27) ss << "27 "; else if(s[i] == -28) ss << "28 "; else if(s[i] == -10) ss << "29 "; } string s2 = ss.str();

Permalänk

Så långt är jag med, det är när jag vill göra en funktion som jag kan kalla genom f(x); som jag snurrar bort det, totalt. För, om jag skulle skriva in det där någonstans i programmets kropp så skulle det bli jäkligt stort och oöverskådligt, något som jag helst undviker.

Så, vad heter det när man skapar en "resursfil" där funktionen för att ersätta tecknena ligger som man sen kallar i programmet genom f(x);? Det så jag kan läsa, öva och läsa lite till.

Mvh

Permalänk
Hedersmedlem

"Resursfiler" är snarare något som används för att lagra bilder, textsträngar och liknande; för att flytta funktioner används vanligen helt enkelt fler .cpp-filer eller bibliotek (statiska eller dynamiska). Du kan till exempel skapa funktionen fkn av ovanstående:

string fkn(string s) { stringstream ss; for(int i = 0; i < s.size(); ++i) { if(s[i] >= 'a' && s[i] <= 'z') ss << s[i]-'a'+1 << " "; else if(s[i] == ' ') ss << " "; else if(s[i] == -27) ss << "27 "; else if(s[i] == -28) ss << "28 "; else if(s[i] == -10) ss << "29 "; } return ss.str(); }

och antingen lägga den högst upp i samma fil som "main" definieras i eller också i en egen. I det senare fallet måste man dock tala om att funktionen finns även i main-filen, till exempel genom att skriva

string fkn(string);

innan funktionen används eller, ännu lämpligare, genom att skapa en matchande header-fil och inkludera denna i main-filen. Man skulle kunna tänka sig följande:
===== fkn.h ======

#ifndef FKN_H #define FKN_H #include <string> std::string fkn(std::string); #endif

===== fkn.cpp ======

#include "fkn.h" #include <string> #include <sstream> using namespace std; string fkn(string s) { stringstream ss; for(int i = 0; i < s.size(); ++i) { if(s[i] >= 'a' && s[i] <= 'z') ss << s[i]-'a'+1 << " "; else if(s[i] == ' ') ss << " "; else if(s[i] == -27) ss << "27 "; else if(s[i] == -28) ss << "28 "; else if(s[i] == -10) ss << "29 "; } return ss.str(); }

===== main.cpp ======

#include "fkn.h" #include <string> using namespace std; int main(int argc, char** argv) { string s = "test abcdåäö"; string s2 = fkn(s); return 0; }

Man får sedan se till att både main.cpp och fkn.cpp kompileras, till exempel genom att inkludera båda i det aktuella projektet (om man kör visual c++).

Permalänk

Tack så hemskt mycket för hjälpen & jag förstår det!

Två saker jag funderar över, det är hur stringstream fungerar, den bygger upp en ny sträng (ersätter) med den nya bokstaven man väljer på den "gamla" platsen. Typ, if(s[i] == 'A') å den hittas på s[23] == 'A' så kommer den ersätta med det jag vill i den nya strängen på plats 23? Eller har jag snurrat bort mig helt?

Det andra jag undrar över är int main(int argc, char** argv), vad gör dessa stjärnor där? Vad fyller de för funktion? Då jag inte vet vad de heter så kan jag varken googla eller slå upp i min 'grekiska' bok för "nybörjare".

Tacksam för svar (:

Permalänk
Medlem

argc innehåller i heltal hur många parametrar som blir inskickade till programmet (main) och char** är en dubbelpekare allokerad som en array av char* som innehåller parametrarna.

Man kan skriva tex "mittprogram.exe wee woo" i en kommandotolk, då kommer argv innehålla wee och woo och argc ökas på. Dock brukar den första platsen vara ifylld med sökvägen till filen eller arbetskatalogen...

Permalänk
Hedersmedlem
Skrivet av Bluetiger:

Två saker jag funderar över, det är hur stringstream fungerar, den bygger upp en ny sträng (ersätter) med den nya bokstaven man väljer på den "gamla" platsen. Typ, if(s[i] == 'A') å den hittas på s[23] == 'A' så kommer den ersätta med det jag vill i den nya strängen på plats 23? Eller har jag snurrat bort mig helt?

stringstream fungerar som andra strömmar (till exempel cout), men arbetar mot en textsträng istället för till exempel terminalen. Lämpliga användningsområden är att bygga upp textsträngar eller att konvertera mellan olika datatyper (som i det här fallet mellan heltal och textsträngar).

stringstream ss; string s; ss << "a " << 1 << " b " << 2 << " c " << 3; s = ss.str(); //s kommer nu innehålla det som skickades in ovan, dvs. "a 1 b 2 c 3"

Permalänk

En sån här tråd är inte riktigt komplett utan att nämna c++ standardens transform. Här är ett exempel på hur den kan användas

#include <iostream> #include <string> #include <algorithm> using namespace std; char my_translate(char c) { switch(c) { case 'a': return 'b'; case 'b': return 'a'; } return c; } int main(int argc, char **argv) { string test = "testare"; transform(test.begin(), test.end(), test.begin(), my_translate); cout << test << endl; return 0; }

Permalänk
Medlem

Går annars lösa med följande:

#include <stdio.h> #define len(x) (sizeof x / (sizeof x[0])) /* Fördel: Funkar för alla konstiga layouter som kan finnas, dock så är den lite jobbare att skriva, * Elgots lösning funkar så länge som layouten är vettigt alianad. Så på din dator blir det samma. */ int table[] = { ['a'] = 1, ['b'] = 2, ['c'] = 3, }; int translate(char c){ return table[c]; } int main(int argc, char **argv) { int i,t; char test[] = "ab c"; for(i = 0; i < len(test) - 1; i++){ if(test[i] == ' '){ printf(" "); } else { printf("%d ", translate(test[i])); } } }

Skriven i C då jag inte har någon c++ kompilator. char test[] är typ samma som string typ.

Visa signatur

Plan9 fan. In glenda we trust.

Permalänk
Hedersmedlem
Skrivet av jop_the_jopsan:

En sån här tråd är inte riktigt komplett utan att nämna c++ standardens transform. Här är ett exempel på hur den kan användas

Det som komplicerar är att vissa tecken skall ersättas med två andra tecken.

Permalänk

Nu förstår jag den delen. Jag tänkte ta det ett steg längre. (sitter å skriver program för att öva & lära mig)
Det jag tänker på nu är om man t.ex. kör

string a; cout << "Ange tecken: "; // Här matas "hej tja goddag apa" in getline(cin,a);

Det jag tänkte då är att man skulle kunna ersätta en del utav den här strängen (apa t.ex.) med banan.
Jag har tidigare löst det på så vis att man att inmatningen delas upp i:

ïnt ant_ord; string a[1000]; // t.ex. cout << "Ange hur många ord du vill ersätta: "; cin >> ant_ord; for(int b = 0; ant_ord > b; b++) { cout << "Ange orden du vill ersätta: "; cin >> a[b]; // Nu läser den alltså in ord för ord in i a, korrekt? Å kan därför ropas på genom t.ex. a[1] osv? }

Det jag undrar är i princip, går det på något vis att kunna använda kommandot getline(); och med hjälp av blanksteg bilda mindre strängar av den stora?

Säg att jag man använder sig utav getline(cin,a); på inmatningen "apa katt mus kisse ko", går det då att få så a[0] = apa, a[1] = katt, a[2] = mus?

Permalänk
Hedersmedlem
Skrivet av Bluetiger:

Det jag undrar är i princip, går det på något vis att kunna använda kommandot getline(); och med hjälp av blanksteg bilda mindre strängar av den stora?

Även här går det utmärkt att använda stringstream (och kanske vill du använda en vector istället för ett string-fält):

vector<string> a; stringstream ss; string s; getline(cin, s); ss << s; while(ss >> s) a.push_back(s);

Permalänk
Skrivet av Elgot:

Även här går det utmärkt att använda stringstream (och kanske vill du använda en vector istället för ett string-fält):

vector<string> a; stringstream ss; string s; getline(cin, s); ss << s; while(ss >> s) a.push_back(s);

Det där förstod jag föga av, jag byggde upp nåt eget, lite mer udda skulle jag väl vilja påstå.

string a; stringstream ss; getline(cin,a); for(int i = 0; i < a.size(); i++) { if(a[i] != ' ') { ss << a[i];} else if(a[i] == ' '){ i++; } }

Det där programmet tar bort alla tänkbara mellanslag, vad jag märkt. Nu ska jag bara lyckas lista ut hur jag meckar ihop så att den vid varje påhittat mellanslag gör så att den börjar på nytt. Typ.

Går det att typ följande:

string a; stringstream ss; int b = 0; getline(cin,a); for(int i = 0; i < a.size(); i++) { if(a[i] != ' ') { ss[b] << a[i]; } else if(a[i] == ' '){ f(ss[b]); i++; b++; } }

Så med andra ord så skriver den till stringstream ss[0] till en början, vid påhittat mellanslag så ökar b i värde till 1. Och den skriver fr.o.m. då till ss[1]?

Permalänk
Hedersmedlem
Skrivet av Bluetiger:

Det där förstod jag föga av, jag byggde upp nåt eget, lite mer udda skulle jag väl vilja påstå.

Strömmar (cout, cin, stringstream och liknande) har den i det här fallet trevliga egenskapen att de normalt betraktar vita tecken som separatorer. Därför kan man till exempel skriva

string a, b; cin >> a >> b;

för att mata in två ord från terminalen och därför kommer

while(ss >> s) a.push_back(s);

att så länge det går att plocka ut ord ur den sträng som skickades till ss lägga dessa sist i a.

Permalänk

Den försöker alltså lägga till i vektorn a tills första mellanslaget är hittat? Och den börjar alltså, därefter, att fylla ett nytt element?

Permalänk
Hedersmedlem
Skrivet av Bluetiger:

Den försöker alltså lägga till i vektorn a tills första mellanslaget är hittat? Och den börjar alltså, därefter, att fylla ett nytt element?

Nja,
ss >> s
plockar ut hela ord (separerade av (godtyckligt många) mellanslag, tabbar, radbrytningar och liknande) från ss och sparar i s tills fel uppstår (till exempel att man når slutet i ss eller att konvertering från string till string misslyckas (detta händer förvisso inte, men om s till exempel hade varit en int istället hade det kunnat vara intressant)). När s väl har tilldelats ett ord sparas detta i vektorn.