//Defining the class
class Hangman
{
private:
vector<string> dictionary; //stores all the words
vector<string> secretWord; //stores the secret word
vector<string> misses; //keeps record of wrong guesses
vector<string> displayVector; //Stores "_"
string originalWord; //stores a copy of secret word to display at the
end of game.
bool gameOver = false; //Flag to check if the player lost or
still in the game.
int totalAttempts;
public:
void selectRandWord();
};
//This is the function i am having problem in.
void Hangman::selectRandWord()
{
secretWord.clear();
//word is a basic string that stores a random word. lets say "Hello World".
string word;
srand(time(NULL));
int random = (rand() % dictionary.size()) + 1;
//I store a random word from vector to word.
word = dictionary[random];
transform(word.begin(), word.end(), word.begin(), ::tolower);
originalWord = word;
for (int index = 0; index < word.length(); index++)
{
//This line has the error: [Error] invalid user-defined conversion from 'char' to 'std::vectorstd::basic_string<char >::value_type&& {aka std::basic_string&&}' [-fpermissive]
//What I am trying to do is take each character from word(for example: "H") and push it back into the vector string secretWord.
secretWord.push_back(word[index]);
}
}
Your secretWord is now a vector<string> type, so it's a collection of possibly many words, I'm not sure if that's what you really intend to have judging by the name. If it indeed is ok and you want to store every single character from word as a separate string in secretWord, then you need to replace push_back call with emplace_back call as the other method actually does two things at a time: constructs a string from the char you pass to it and appends the string to the end of the container, like this
secretWord.emplace_back(1, word[index]);
Mere push_back fails because it needs to be provided with an object of the type your vector stores, so you could also solve your problem by explicitly constructing a string from your char:
secretWord.push_back(string(1, word[index]));
I suggest you give a read to these: emplace back reference and push back reference if you're interested in copy/move details.
I have a string coming from PC through serial to a microcontroller (Arduino), e.g.:
"HDD: 55 - CPU: 12.6 - Weather: Cloudy [...] $";
by this function I found:
String inputStringPC = "";
boolean stringCompletePC = false;
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
inputStringPC += inChar;
if (inChar == '$') // end marker of the string
{
stringCompletePC = true;
}
}
}
I would like to extract the first number of it after the word HDD, CPU and also get the string after Weather (ie "cloudy"); my thinking is something like that:
int HDD = <function that does that>(Keyword HDD);
double CPU = <function that does that>(Keyword CPU);
char Weather[] = <function that does that>(Keyword Weather);
What is the right function to do that?
I looked into inputStringSerial.indexOf("HDD") but I am still a learner to properly understand what it does and don't know if theres a better function.
My approach yielded some syntax errors and confused me with the difference in usage between "String inputStringSerial" (class?) and "char inputStringSerial[]" (variable?). When I do 'string inputStringSerial = "";' PlatformIO complains that "string" is undefined. Any help to understand its usage here is greatly appreciated.
Thanks a bunch.
The String class provides member functions to search and copy the contents of the String. That class and all its member functions are documented in the Arduino Reference:
https://www.arduino.cc/reference/tr/language/variables/data-types/stringobject/
The other way a list of characters can be represented is a char array, confusingly also called a string or cstring. The functions to search and copy the contents of a char array are documented at
http://www.cplusplus.com/reference/cstring/
Here is a simple Sketch that copies and prints the value of the Weather field using a String object. Use this same pattern - with different head and terminator values - to copy the string values of the other fields.
Once you have the string values of HDD and CPU, you'll need to call functions to convert those string values into int and float values. See the String member functions toInt() and toFloat() at
https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/toint/
or the char array functions atoi() and atof() at
http://www.cplusplus.com/reference/cstdlib/atoi/?kw=atoi
String inputStringPC = "HDD: 55 - CPU: 12.6 - Weather: Cloudy [...] $";
const char headWeather[] = "Weather: "; // the prefix of the weather value
const char dashTerminator[] = " -"; // one possible suffix of a value
const char dollarTerminator[] = " $"; // the other possible suffix of a value
void setup() {
int firstIndex; // index into inputStringPC of the first char of the value
int lastIndex; // index just past the last character of the value
Serial.begin(9600);
// find the Weather field and copy its string value.
// Use similar code to copy the values of the other fields.
// NOTE: This code contains no error checking for unexpected input values.
firstIndex = inputStringPC.indexOf(headWeather);
firstIndex += strlen(headWeather); // firstIndex is now the index of the char just past the head.
lastIndex = inputStringPC.indexOf(dollarTerminator, firstIndex);
String value = inputStringPC.substring(firstIndex, lastIndex);
Serial.print("Weather value = '");
Serial.print(value);
Serial.println("'");
}
void loop() {
// put your main code here, to run repeatedly:
}
When run on an Arduio Uno, this Sketch produces:
Weather value = 'Cloudy [...]'
How do I concatenate strings in solidity?
var str = 'asdf'
var b = str + 'sdf'
seems not to work.
I looked up the documentation and there is not much mentioned about string concatenation.
But it is stated that it works with the dot ('.')?
"[...] a mapping key k is located at sha3(k . p) where . is concatenation."
Didn't work out for me too. :/
An answer from the Ethereum Stack Exchange:
A library can be used, for example:
import "github.com/Arachnid/solidity-stringutils/strings.sol";
contract C {
using strings for *;
string public s;
function foo(string s1, string s2) {
s = s1.toSlice().concat(s2.toSlice());
}
}
Use the above for a quick test that you can modify for your needs.
Since concatenating strings needs to be done manually for now, and doing so in a contract may consume unnecessary gas (new string has to be allocated and then each character written), it is worth considering what's the use case that needs string concatenation?
If the DApp can be written in a way so that the frontend concatenates the strings, and then passes it to the contract for processing, this could be a better design.
Or, if a contract wants to hash a single long string, note that all the built-in hashing functions in Solidity (sha256, ripemd160, sha3) take a variable number of arguments and will perform the concatenation before computing the hash.
You can't concatenate strings. You also can not check equals (str0 == str1) yet. The string type was just recently added back to the language so it will probably take a while until all of this works. What you can do (which they recently added) is to use strings as keys for mappings.
The concatenation you're pointing to is how storage addresses are computed based on field types and such, but that's handled by the compiler.
Here is another way to concat strings in Solidity. It is also shown in this tutorial:
pragma solidity ^0.4.19;
library Strings {
function concat(string _base, string _value) internal returns (string) {
bytes memory _baseBytes = bytes(_base);
bytes memory _valueBytes = bytes(_value);
string memory _tmpValue = new string(_baseBytes.length + _valueBytes.length);
bytes memory _newValue = bytes(_tmpValue);
uint i;
uint j;
for(i=0; i<_baseBytes.length; i++) {
_newValue[j++] = _baseBytes[i];
}
for(i=0; i<_valueBytes.length; i++) {
_newValue[j++] = _valueBytes[i];
}
return string(_newValue);
}
}
contract TestString {
using Strings for string;
function testConcat(string _base) returns (string) {
return _base.concat("_Peter");
}
}
You have to do it manually for now
Solidity doesn't provide built-in string concatenation and string comparison.
However, you can find libraries and contracts that implement string concatenation and comparison.
StringUtils.sol library implements string comparison.
Oraclize contract srtConcat function implements string concatenation.
If you need concatenation to get a hash of a result string, note that there are built-in hashing functions in Solidity: sha256, ripemd160, sha3. They take a variable number of arguments and perform the concatenation before computing the hash.
You could leverage abi.encodePacked:
bytes memory b;
b = abi.encodePacked("hello");
b = abi.encodePacked(b, " world");
string memory s = string(b);
// s == "hello world"
I used this method to concat strings. Hope this is helpful
function cancat(string memory a, string memory b) public view returns(string memory){
return(string(abi.encodePacked(a,"/",b)));
}
you can do it very easily with the low-level function of solidity with
abi.encodePacked(str,b)
one important thing to remember is , first typecast it to string ie:
string(abi.encodePacked(str, b))
your function will return
return string(abi.encodePacked(str, b));
its easy and gas saving too :)
Solidity does not offer a native way to concatenate strings so we can use abi.encodePacked(). Please refer Doc Link for more information
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
contract AX{
string public s1 = "aaa";
string public s2 = "bbb";
string public new_str;
function concatenate() public {
new_str = string(abi.encodePacked(s1, s2));
}
}
In solidity, working with a string is a headache. If you want to perform string action, you have to consider converting string to byte and then convert back to string again. this demo contract will concatenate strings
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract String{
function concatenate(string memory firstName,string memory lastName) public pure returns (string memory fullName) {
bytes memory full=string.concat(bytes(firstName),bytes(lastName));
return string(full);
}
}
Examples above do not work perfect.
For example, try concat these values
["10","11","12","13","133"] and you will get ["1","1","1","1","13"]
There is some bug.
And you also do not need use Library for it. Because library is very huge for it.
Use this method:
function concat(string _a, string _b) constant returns (string){
bytes memory bytes_a = bytes(_a);
bytes memory bytes_b = bytes(_b);
string memory length_ab = new string(bytes_a.length + bytes_b.length);
bytes memory bytes_c = bytes(length_ab);
uint k = 0;
for (uint i = 0; i < bytes_a.length; i++) bytes_c[k++] = bytes_a[i];
for (i = 0; i < bytes_b.length; i++) bytes_c[k++] = bytes_b[i];
return string(bytes_c);
}
You can do this with the ABI encoder. Solidity can not concatenate strings natiely because they are dynamically sized. You have to hash them to 32bytes.
pragma solidity 0.5.0;
pragma experimental ABIEncoderV2;
contract StringUtils {
function conc( string memory tex) public payable returns(string
memory result){
string memory _result = string(abi.encodePacked('-->', ": ", tex));
return _result;
}
}
Compared to languages such as Python and JavaScript, there is no direct way of doing this in Solidity. I would do something like the below to concatenate two strings:
//SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 < 0.9.0;
contract test {
function appendStrings(string memory string1, string memory string2) public pure returns(string memory) {
return string(abi.encodePacked(string1, string2));
}
}
Please see the screenshot below for the result of concatenating two strings ('asdf' and 'sdf') in Remix Ethereum IDE.
You can use this approach to concat and check equal string.
// concat strgin
string memory result = string(abi. encodePacked("Hello", "World"));
// check qual
if (keccak256(abi.encodePacked("banana")) == keccak256(abi.encodePacked("banana"))) {
// your logic here
}
After 0.8.4 version of Solidity, you can now concat bytes without using encodePacked()
See the issue: here
//SPDX-License-Identifier: GPT-3
pragma solidity >=0.8.4;
library Strings {
function concat(string memory a, string memory b) internal pure returns (string memory) {
return string(bytes.concat(bytes(a),bytes(b)));
}
}
Usage:
contract Implementation {
using Strings for string;
string a = "first";
string b = "second";
string public c;
constructor() {
c = a.concat(b); // "firstsecond"
}
}
I strings in the format of name:key:dataLength:data and these strings can often be chained together. for example "aNum:n:4:9879aBool:b:1:taString:s:2:Hi" this would map to an object something like:
{
aNum: 9879,
aBool: true,
aString: "Hi"
}
I have a method for parsing a string in this format but I'm not sure whether it's use of substring is the most efficient way of pprocessing the string, is there a more efficient way of processing strings in this fashion (repeatedly chopping off the front section):
Map<string, dynamic> fromString(String s){
Map<String, dynamic> _internal = new Map();
int start = 0;
while(start < s.length){
int end;
List<String> parts = new List<String>(); //0 is name, 1 is key, 2 is data length, 3 is data
for(var i = 0; i < 4; i++){
end = i < 3 ? s.indexOf(':') : num.parse(parts[2]);
parts[i] = s.substring(start, end);
start = i < 3 ? end + 1 : end;
}
var tranType = _tranTypesByKey[parts[1]]; //this is just a map to an object which has a function that can convert the data section of the string into an object
_internal[parts[0]] = tranType._fromStr(parts[3]);
}
return _internal;
}
I would try s.split(':') and process the resulting list.
If you do a lot of such operations you should consider creating benchmarks tests, try different techniques and compare them.
If you would still need this line
s = i < 3 ? s.substring(idx + 1) : s.substring(idx);
I would avoid creating a new substring in each iteration but instead just keep track of the next position.
You have to decide how important performance is relative to readability and maintainability of the code.
That said, you should not be cutting off the head of the string repeatedly. That is guaranteed to be inefficient - it'll take time that is quadratic in the number of records in your string, just creating those tail strings.
For parsing each field, you can avoid doing substrings on the length and type fields. For the length field, you can build the number yourself:
int index = ...;
// index points to first digit of length.
int length = 0;
int charCode = source.codeUnitAt(index++);
while (charCode != CHAR_COLON) {
length = 10 * length + charCode - 0x30;
charCode = source.codeUnitAt(index++);
}
// index points to the first character of content.
Since lengths are usually small integers (less than 2<<31), this is likely to be more efficient than creating a substring and calling int.parse.
The type field is a single ASCII character, so you could use codeUnitAt to get its ASCII value instead of creating a single-character string (and then your content interpretation lookup will need to switch on character code instead of character string).
For parsing content, you could pass the source string, start index and length instead of creating a substring. Then the boolean parser can also just read the code unit instead of the singleton character string, the string parser can just make the substring, and the number parser will likely have to make a substring too and call double.parse.
It would be convenient if Dart had a double.parseSubstring(source, [int from = 0, int to]) that could parse a substring as a double without creating the substring.
I wrote this function that uses a binary search to look for a specific value in an array of structs. Why doesn't it compile?
I'm getting this error:
prog.c:224: error: subscripted value is neither array nor pointer
prog.c:226: error: subscripted value is neither array nor pointer
This is the function:
int FieldSearch(Field *pArr, int size, int val)
{
int low=0,high=size-1, middle;
while (low <= high)
{
middle = (low + high)/2;
if (val == pArr->Id[middle])
return middle;
else if (val < pArr->Id[middle])
high = middle -1;
else
low = middle +1;
}
return NOT_FOUND;
}
This is the field struct:
typedef struct field
{
char Id;
Coordinates location;
int area;
int price;
} Field;
Maybe the prototype is wrong...
Your problem is this statement:
pArr->Id[middle]
It looks like, but I don't have nearly enough info, that your member Id is not a pointer or an array, but merely a variable. So you cannot access it with an operator[]. You should show us what this Field object looks like.
I'm guessing you should do something like this
(pArr + middle)->Id so this will access the element of the Field array you passed into your function. Then you do have to pass in an actual array of Field structures, for this to work.
If you want to search the "array" pArr, you need to put the brackets directly behind the identitifier. This should work:
pArr[middle].Id