c++ How to check string parsing order - c++11

I am a beginner in c++. I have multi line input from command line like below.
A {1,2,3,4}
B {2,1,4,9}
c {5,8,7,6}
My aim is to read each line and to do some action based on the first letter in line. I have a code like below.
while(getline(cin,input)){
stringstream ss(input);
string letter;
while(!ss.eof()){
ss >> letter;
if (letter == "A")
{
Do this
}
if (letter == "B")
{
Do this
}
if (letter== "C")
{
Do this
}
}
}
Now I want to ensure that after A, only B has to be given as input and not A again or C. After B and C input can be in any order. Is there any easy way to check the order of input?

Related

How to loop through a folder with conditional statement in Stata?

I have a folder with a bunch of csv files and I want to loop through each file, check if a list of variables in each of the files = 0, then save the csv file as a .dta if they do not equal 0.
I'm having trouble finding online help to do this but here's what I've tried so far:
foreach file in `files' {
import delimited using `file', clear
if a & b & c & d != 0
save "Desktop\myfolder\`file'.dta"
}
when I try this though Stata tells me "{ required r(100)".
Any help appreciated. Thanks.
Stealing some code from the estimable #Wouter Wakker, let's first suppose that the criterion is that a non-zero value is found somewhere in a b c d
foreach file in `files' {
import delimited using `file', clear
local OK = 0
quietly foreach v in a b c d {
count if `v' != 0
if r(N) > 0 local OK = 1
}
if `OK' save "Desktop/myfolder/`file'.dta"
}
Whatever your precise criterion, I think you need to loop over a b c d and (say) count or summarize according to what you want or do not want.
From help ifcmd:
Syntax
if exp { or if exp single_command
multiple_commands
}
So you can do either
foreach file in `files' {
import delimited using `file', clear
if a & b & c & d != 0 save "Desktop\myfolder\`file'.dta"
}
or
foreach file in `files' {
import delimited using `file', clear
if a & b & c & d != 0 {
save "Desktop\myfolder\`file'.dta"
}
}
However, I don't think your if condition does what you think it does. What you're looking for would rather be:
if a != 0 & b != 0 & c != 0 & d != 0

How to use boost::spirit to modify a string like regex does?

I'm writing a little Domain Specific Language for my program, using JUCE::JavascriptEngine as the scripting engine. This takes a string as input and then parses it, but I need to do some pre-processing on the string to adapt it from my DSL to JavaScript. The pre-processing mainly consists of wrapping some terms inside functions, and placing object names in front of functions. So, for instance, I want to do something like this:
take some special string input "~/1/2"...
wrap it inside a function: "find("~/1/2")"...
and then attach an object to it: "someObject.find("~/1/2")" (the object name has to be a variable).
I've been using regex for this (now I have two problems...). The regexes are getting complicated and unreadable, and it's missing a lot of special cases. Since what I'm doing is grammatical, I thought I'd upgrade from regex to a proper parser (now I have three problems...). After quite a lot of research, I chose Boost.Spirit. I've been going through the documentation, but it's not taking me in the right direction. Can someone suggest how I might use this library to manipulate strings in the way I am looking for? Given that I am only trying to manipulate a string and am not interested in storing the parsed data, do I need to use karma for the output, or can I output the string with qi or x3, during the parsing process?
If I'm headed down the wrong path here, please feel free to re-direct me.
This seems too broad to answer.
What you're doing is parsing input, and transforming it to something else. What you're not doing is find/replace (otherwise you'd be fine using regular expressions).
Of course you can do what regular expressions do, but I'm not sure it buys you anything:
template <typename It, typename Out>
Out preprocess(It f, It l, Out out) {
namespace qi = boost::spirit::qi;
using boost::spirit::repository::qi::seek;
auto passthrough = [&out](boost::iterator_range<It> ignored, auto&&...) {
for (auto ch : ignored) *out++ = ch;
};
auto transform = [&out](std::string const& literal, auto&&...) {
for (auto ch : "someObject.find(\"~"s) *out++ = ch;
for (auto ch : literal) *out++ = ch;
for (auto ch : "\")"s) *out++ = ch;
};
auto pattern = qi::copy("\"~" >> (*~qi::char_('"')) >> '"');
qi::rule<It> ignore = qi::raw[+(!pattern >> qi::char_)] [passthrough];
qi::parse(f, l, -qi::as_string[pattern][transform] % ignore);
return out;
}
The nice thing about this way of writing it, is that it will work with any source iterator:
for (std::string const input : {
R"(function foo(a, b) { var path = "~/1/2"; })",
})
{
std::cout << "Input: " << input << "\n";
std::string result;
preprocess(begin(input), end(input), back_inserter(result));
std::cout << "Result: " << result << "\n";
}
std::cout << "\n -- Or directly transformed stdin to stdout:\n";
preprocess(
boost::spirit::istream_iterator(std::cin >> std::noskipws), {},
std::ostreambuf_iterator<char>(std::cout));
See it Live On Coliru, printing the output:
Input: function foo(a, b) { var path = "~/1/2"; }
Result: function foo(a, b) { var path = someObject.find("~/1/2"); }
-- Or directly transformed stdin to stdout:
function bar(c, d) { var path = someObject.find("~/1/42"); }
But this is very limited since it will not even do the right thing if such things are parts of comments or multiline strings etc.
So instead you probably want a dedicated library that knows how to parse javascript and use it to do your transformation, such as (one of the first hits when googling tooling library preprocess javascript transform): https://clojurescript.org/reference/javascript-library-preprocessing

Reading from a .txt file and looping until new line

I am having trouble understanding the output of my very little program which should read characters from a text file until it finds a new line.
It correctly outputs the characters and stops, but I don't understand why it still outputs the newline ('\n) character in the terminal and doesn't end before getting to it.
I know that I could use getline() or find another way but I would really understand the reason behind this behaviour.
Thank you in advance!
Edo
Code:
int main() {
std::ifstream in_file;
in_file.open("../responses.txt");
char c;
while(c != '\n'){
in_file.get(c);
std::cout << c << std::endl;
}
return 0;
}
Output:
A
B
C
D
E
Time elapsed: 000:00:000
The

Why does a newline character count as two keys in a BTreeMap?

I'm creating a compression/decompression library in Rust using Huffman encoding. One of the first steps is creating a data structure that contains all unique characters and the number of occurrences. I'm starting with just a simple text file, and having issues related to newline 'characters'.
My first attempt at solving this problem was constructing a BTreeMap, essentially a key-value pair of unique characters and their occurrences, respectively. Unfortunately, a newline 'character' is \n, which I think is not being handled corrected due to being two characters. I then converted the BTreeMap into a Vec to order by value, but that didn't solve the newline issue.
Here's my initial attempt at my comp binary package. Calling the binary is done using cargo, and my sample file is reproduced at the end of this question:
cargo run <text-file-in> <compressed-output-file>
main.rs
extern crate comp;
use std::env;
use std::process;
use std::io::prelude::*;
use comp::Config;
fn main() {
// Collect command-line args into a vector of strings
let mut stderr = std::io::stderr();
let config = Config::new(env::args()).unwrap_or_else(|err| {
writeln!(&mut stderr, "Parsing error: {}", err).expect("Could not write to stderr");
process::exit(1)
});
println!("Filename In: {}", config.filename_in);
println!("Filename Out: {}", config.filename_out);
if let Err(e) = comp::run(config) {
writeln!(&mut stderr, "Application error: {}", e).expect("Could not write to stderr");
process::exit(1);
}
}
lib.rs
use std::collections::btree_map::BTreeMap;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::iter::FromIterator;
pub struct Config {
pub filename_in: String,
pub filename_out: String
}
impl Config {
pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
args.next();
let filename_in = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a filename_in string"),
};
let filename_out = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a filename_out string"),
};
Ok(Config {
filename_in: filename_in,
filename_out: filename_out,
})
}
}
pub fn run(config: Config) -> Result<(), Box<Error>> {
let mut f = File::open(config.filename_in)?;
let mut contents = String::new();
f.read_to_string(&mut contents)?;
for line in contents.lines() {
println!("{}", line);
}
// Put unique occurrences into a BTreeMap
let mut count = BTreeMap::new();
for c in contents.chars() {
*count.entry(c).or_insert(0) += 1;
}
// Put contents into a Vec to order by value
let mut v = Vec::from_iter(count);
v.sort_by(|&(_, a), &(_, b)| b.cmp(&a));
// Print key-value pair of input file
println!("Number of occurrences of each character");
for &(key, value) in v.iter() {
println!("{}: {}", key, value);
}
Ok(())
}
Sample text file, poem.txt:
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us — don't tell!
They'd banish us, you know.
How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!
Usage:
$ cargo run poem.txt poem
Compiling comp v0.1.0 (file:///home/chris/Projects/learn_rust/comp-rs)
Finished dev [unoptimized + debuginfo] target(s) in 1.96 secs
Running `target/debug/comp poem.txt poem`
Filename In: poem.txt
Filename Out: poem
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us — don't tell!
They'd banish us, you know.
How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!
Number of occurrences of each character
: 36
o: 24
e: 15
a: 10
n: 10
y: 10
< What's going on here?
: 9 < What's going on here?
r: 9
d: 8
l: 8
b: 7
i: 7
t: 7
u: 7
h: 6
s: 5
!: 4
': 4
T: 4
g: 4
m: 4
,: 3
w: 3
?: 2
H: 2
f: 2
k: 2
p: 2
.: 1
A: 1
I: 1
W: 1
c: 1
v: 1
—: 1
Unfortunately, a newline 'character' is \n, which I think is not being handled corrected due to being two characters.
No, it is not. A newline character (UTF-8 codepoint 0x0A) is a single character.
I think I need to newline character to be a key in my key-value pair, but it's currently two keys.
No, it is not. Such a thing cannot happen "accidentally" either. If we somehow had two keys, you would have to call insert twice; there's no built-in concept of a multi-key map.
All that's happening here is that a newline character is printed as... a newline!
y: 10
: 9
If you take the time to create a MCVE, you'd see this quickly:
fn main() {
let c = '\n';
println!(">{}<", c);
println!(">{:?}<", c);
}
>
<
>'\n'<
The newline character is actually an escape sequence character. This means that if you write it as \n in the code which shows up as two characters, it's actually a placeholder for a single character - a new line - and should be treated as 'one character' in the program during runtime.
The core issue you have here is that you're using println to print it out to the command line and actually printing an new line, as the \n is interpreted to mean "A new line". This is why, when you use println here, you get the behavior you see. This is typical of most languages.
While this adds a little additional bit of code, you may wish to do something like this instead to specially-handle new-line data being printed:
// Print key-value pair of input file
println!("Number of occurrences of each character");
for &(key, value) in v.iter() {
if key == '\n' {
println!("\\n": {}, value);
} else {
println!("{}: {}", key, value);
}
}
Consider as explained by Shepmaster though to create an MCVE to thoroughly test things, it helps rule out misinterpretation of what is actually happening behind the scenes.
(NOTE: I am not a Rust master; there is probably a better way to achieve the above, but this is the shortest solution I came up with in a short period of time)

How to remove line `v u` from a file when line `u v` already exists using unix command

I have the following test data :
a b
a c
b a
b c
b d
c a
c b
c d
d b
d c
and I want to remove lines v u when line u v already exists using unix command. For example here I want to obtain :
a b
a c
b c
b d
c d
I've tried with an awk script but on a long file it takes too much time :
{
if(NR==1){
n1=$1
n2=$2
test=0
k=0
i = 0
column1[i]=$1
column2[i]=$2
printf "%s %s\n", column1[i], column2[i]
}
else{
for(k=0; k<=i;k++){
if(column1[k]==$2){
test=1
tmp=i
break
}
}
if(test==1){
if(column2[tmp]==$1){
n1=$1
n2=$2
}
}
else if(n1!=$1||n2!=$2){
n1=$1
n2=$2
i++
column1[i]=$1
column2[i]=$2
printf "%s %s\n", column1[i], column2[i]
}
test=0
}
}
Does someone have an idea ?
I think this can be achieved pretty simply:
awk '!seen[$1,$2]++ && !seen[$2,$1]' file
This only prints lines (the default action) when the first and second column have not yet been seen in either order.
The array seen keeps track of every pair of fields by setting a key containing the first and second field. The expression !seen[key]++ is only true the first time that a specific key is tested because the value in the array is incremented each time.

Resources