Match a For Loop Using a Regex - regex

I Want to match the below Code with my Regex,
Simply say I want to match the whole for loop statement starting from for and ending with the }.
This is what I tried, but In my approach I have to give \R exactly the same times as the number of lines in the for loop, Can it be dynamic ? Or is there a better solution.
Please tell me
Here is my code for Regex
for.+\(.*\R.*\R.*\R.*\R.*\R.*\R.*
And this is what I want to match
for (i = 2; i <= n / 2; ++i) {
// condition for non-prime
if (n % i == 0) {
flag = 1;
break;
}
}

Here's an example using AWK - it uses Regex for the matching, and some logic for the { in and } out processing.
awk 'BEGIN { infor=0; }
/for *\(.*{/ { infor++; print $0; next; }
/^.*$/ { if (infor) { print $0; } }
/{/ { if (infor) { infor++; } }
/}/ { if (infor) { infor--; } }'
Given this input -
What the AWK man
for (i = 2; i <= n / 2; ++i) {
// condition for non-prime
if (n % i == 0) {
flag = 1;
break;
}
}
echo ME
Echo you
for (i = 2; i <= n / 2; ++i) {
// condition for non-prime
if (n % i == 0) {
flag = 1;
break;
}
}
it gives this output of just the for loops.
for (i = 2; i <= n / 2; ++i) {
// condition for non-prime
if (n % i == 0) {
flag = 1;
break;
}
}
for (i = 2; i <= n / 2; ++i) {
// condition for non-prime
if (n % i == 0) {
flag = 1;
break;
}
}

You can try this regex :
#!/usr/bin/env bash
grep -z -Po '(?s)[ \t]*for [^{]+{[^{}]+condition for non-prime[^}]+}[^}]+}' << EOF
for (i = 2; i <= n / 2; ++i) {
// Different comment
if (n % i == 0) {
flag = 1;
break;
}
}
for (i = 2; i <= n / 2; ++i) {
// condition for non-prime
if (n % i == 0) {
flag = 1;
break;
}
}
other stuff

An issue with your requirement is the possibility of unmatched braces (in comments or strings):
// This comment line will break the search of matching } pairs
print "And a message with a single } fails too."
When the code is well indented (perhaps some code formatting tool in your IDE), you can try a solution using the indents:
sed -rz 's/.*(^|\n)(\s*)(for[^\n]*\n)((\2[^}][^\n]*\n)*[^\n]*).*/\2\3\4\n/' inputfile
This will fail for loops with an empty line and will only extract the last loop from the file. I won't explain the command, using regex for your task is too complex.
When you know how much spaces are used for your indents (of rewrite the next command for tabs), you might try selecting a for-loop without or with 2 spaces indent.
sed -n '/^ for/,/^ }/ p; /^for/,/}/ p' inputfile
This is all guessing and will fail in real life cases. Please think about why you want to extract the for-loops and consider writing a parser that understands the syntax.

Related

stoi() terminate after throwing and instance of 'std::invalid argument in c++-- What am I doing wrong?

Fairly new to coding. Trying some of the easy projects at LeetCode, and failing... Ha! I am trying to take an integer and convert it to a string so I can reverse it, then re-convert the reversed string back into a integer.
This code is throwing the "terminate after throwing and instance of 'std::invalid argument' what(): stoi" error. I've spent an hour searching google and other questions here on SO, but can't figure out why it's not working.
bool isPalindrome(int x) {
std::string backwards ="";
std::string NumString = std::to_string(x);
for (int i = NumString.size(); i >= 0 ; i--) {
backwards += NumString[i];
}
int check = std::stoi(backwards);
if (check == x) {
return true;
}
else {
return false;
}
}
EDIT: I think I figured it out. It was adding the null character to the end of the string upon first conversion, then adding it to the beginning of the string when I reversed it. Spaces can't be converted to integers.
So... I changed this line and it works:
for (int i = NumString.size() - 1; i >= 0 ; i--)
you can also reverse number without using string.
bool isPalindrome(int x) {
long long rev = 0;
int cur = x;
while( cur > 0) {
rev *= 10;
rev += cur % 10;
cur /=10;
}
return rev == x;
}
Its simpler than your answer that you edited in. YOu have
for (int i = NumString.size(); i >= 0 ; i--) {
backwards += NumString[i];
}
Imagine that Numstring has length 3 (no matter what spaces, digits,....)
So now you are efectively doing
for (int i = 3; i >= 0 ; i--) {
backwards += NumString[i];
}
So first loop goes
backwards += NumString[3];
well the indexes of things in an array of length 3 in c++ are 0,1,2. YOu are going one off the end
This is why you see loops doing
for(int i = 0; i < len; i++){}
Note the i < len not i <= len

Time limit Exceeded in if-else

Following is a function which change the value of array according to conditions:
If the difference between the array element and the next multiple of 5 is less than 3, round up to the next multiple of 5.
If the value of array element is less than 38, no rounding occurs.
Code:
vector<int> gradingStudents(vector<int> grades) {
int n = grades.size();
int i = 0;
while(i<n)
{
if(grades.at(i)<38)
{
i++;
}
else if( (grades.at(i)+1) % 5==0 )
{
grades.at(i) += 1;
i++;
}
else if( (grades.at(i)+2) % 5 == 0 && grades.at(i)>=38)
{
grades.at(i) += 2 ;
i++;
}
}
return grades;
}
Hackerrank site saying " Time Limit Exceeded". I don't understand how can time limit exceeded when there is no loop (except the essential while loop). If I remove i++ from each if statement and put it outside all if statements then its working fine, but the no. of statements remain same. please help me out
Time Limit Exceeded happens most often when the input size if very large, and/ or your logic takes a long time to process. One place I see in your code is, if there was a place where no if statements were satisfied, it will never be because i wont be incremented. Basically your loop will run forever.
You can either increment i in the end of the while loop (because anyway you will increment it),
while(i<n)
{
if(grades.at(i)<38)
{
}
else if( (grades.at(i)+1) % 5==0 )
grades.at(i) += 1;
else if( (grades.at(i)+2) % 5 == 0)
grades.at(i) += 2;
i++;
}
Or use a for loop,
for(int i = 0; i < n; i++)
{
if(grades.at(i)<38)
{
}
else if( (grades.at(i)+1) % 5==0 )
grades.at(i) += 1;
else if( (grades.at(i)+2) % 5 == 0)
grades.at(i) += 2;
}
Your code only increments i when one of the conditions is met. It is not clear why you are doing this, because no matter what case the number i is, in the next iteration you want to check the next number not i again. Your conditions are not complete, in the sense that for example i=42 does not match any condition. Hence, your loop will get stuck once it encounters the first such number.
Your current issue of an potentially infinte loop can be solved via
while(i<n)
{
if(grades.at(i)<38)
{
}
else if( (grades.at(i)+1) % 5==0 )
{
grades.at(i) += 1;
}
else if( (grades.at(i)+2) % 5 == 0)
{
grades.at(i) += 2 ;
}
i++;
}
Or the equivalent for loop.

How do I make an ascending function in C++?

I need to make a simple function in c++ that will say if an entered integer has its digits ascending from left to right. Ex, 123 is ascending. We just started learning recurssion, which is what I'm supposed to use, but I'm confused. So far what I was thinking is that you store the last digit as a temp, then compare that to the next digit, but how would you manage to do that?
bool ascending(int n) {
int temp = n % 10;
while (n / 10 > 0) {
n = n / 10;
if (temp > n % 10) {
return false;
break;
}
temp = n % 10;
}
}
This is the code I have so far, but I'm definitely messing up. I'm not even using recurrsion.
Here is one way you can go about it.
On every iteration, you check that last 2 digits are in order. And when the number is a single digit, return true
bool ascending(int n) {
int last_digit = n % 10;
int remainder = n / 10;
if (remainder == 0)
{
return true;
}
int second_last_digit = remainder % 10;
if (last_digit < second_last_digit)
{
return false;
}
else
{
return ascending(remainder); // Recusrive call
}
}

Is it possible to use string::find to detect a new line character?

I am trying to parse a string of 1200 songs and I would like to set my barCount to 0 every time I find a '\n' or my barCount =4. From what I have found online, \n represents one character, but I'm not sure what to do with that information... How can I find it, and then do what I need to do?
int barCount = 0;
size_t start = 0;
size_t n = 0;
int charCount = 0;
while((start = chartDataString.find(" |", start)) != string::npos){
++barCount;
start+=2;
charCount++;
//if(barCount == 3){// || chartDataString.find("]")){
if(chartDataString.find("\n") !=string::npos){
barCount = 0;
}
else if(barCount == 4 || chartDataString[charCount] == ']') {
chartDataString.insert(start, "\n");
barCount = 0;
}
}
Looking at your code, I suspect I understand what you're trying to do now. Let me see if I get this straight:
Each song title/record in your string consists of up to four fields separated by vertical bars
A record may be terminated early by a right-bracket or a newline
If it's not terminated by a newline, insert one.
The following may do a better job:
size_t curr_pos = 0, next_bar, next_nl, next_brk;
int bar_count = 0;
while (true)
{
next_bar = chartDataString.find(" |", curr_pos);
next_nl = chartDataString.find("\n", curr_pos);
next_brk = chartDataString.find("]", curr_pos);
if (next_bar == string::npos &&
next_nl == string::npos &&
next_brk == string::npos)
break;
// Is a newline the next thing we'll encounter?
if (next_nl < next_bar && next_nl < next_brk)
{
curr_pos = next_nl + 1; // skip past newline
bar_count = 0; // reset bar count
}
// Is a vertical bar the next thing we'll encounter?
if (next_bar < next_nl && next_bar < next_brk)
{
bar_count++;
curr_pos = next_bar + 2; // skip past vertical bar
}
// Is a right-bracket the next thing we'll encounter?
if (next_brk < next_bar && next_brk < next_nl)
{
bar_count = 4; // fake like we've seen all 4 bars
curr_pos = next_brk + 1; // skip past bracket
}
// Have we seen 4 vertical bars or a right bracket?
if (bar_count == 4)
{
bar_count = 0;
chartDataString.insert("\n", curr_pos);
curr_pos += 1; // skip the newline we just inserted
}
}
It's a little more verbose, but it tries to break apart all the different conditions. Hopefully, this helps.

Generating all n-letter permutations

I am attempting to calculate all the possible 3 letter permutations, using the 26 letters (Which amounts to only 26*25*24=15,600). The order of the letters matters, and I don't want repeating letters. (I wanted the permutations to be generated in lexicographical order, but that isn't necessary)
So far I attempted to nest for loops, but I ended up iterating through every combination possible. So there are repeating letters, which I do not want, and the for loops can become difficult to manage if I want more than 3 letters.
I can flip through the letters until I get a letter that has not been used, but it isn't in lexicographical order and it is much slower than using next_permutation (I cannot use this std method because I'm left calculating all of the subsets of the 26 letters).
Is there a more efficient way to do this?
To put in perspective of the inefficiency, next_permutation iterates through the first 6 digits instantaneously. However, it takes several seconds to get all the three letter permutations using this method, and next_permutation still quickly becomes inefficient with the 2^n subsets I must calculate.
Here is what I have for the nested for loops:
char key[] = {'a','b','c','d','e','f','g','h','i','j','k',
'l','m','n','o','p','r','s','t','u','v','w','x','y','z'};
bool used[25];
ZeroMemory( used, sizeof(bool)*25 );
for( int i = 0; i < 25; i++ )
{
while( used[i] == true )
i++;
if( i >= 25 )
break;
used[i] = true;
for( int j = 0; j < 25; j++ )
{
while( used[j] == true )
j++;
if( j >= 25 )
break;
used[j] = true;
for( int k = 0; k < 25; k++ )
{
while( used[k] == true )
k++;
if( k >= 25 )
break;
used[k] = true;
cout << key[i] << key[j] << key[k] << endl;
used[k] = false;
}
used[j] = false;
}
used[i] = false;
}
Make a root which represents the start of a combination, so it has no value.
calculate all the possible children (26 letter, 26 children...)
for each root child calculate possible children (so: remaining letters)
use a recursive limited-depth search to find your combinations.
This is a solution I would try if i just want a "simple" solution. I'm not sure how recource intensive this is so I suggest you start trying with a small set of letters.
a = {a...z}
b = {a...z}
c = {a...z}
for each(a)
{
for each(b)
{
for each(c)
{
echo a + b + c;
}
}
}
For a specific and small, n, manual loops like you have is the easiest way. However, your code can be highly simplified:
for(char a='a'; a<='z'; ++a) {
for(char b='a'; b<='z'; ++b) {
if (b==a) continue;
for(char c='a'; c<='z'; ++c) {
if (c==a) continue;
if (c==b) continue;
std::cout << a << b << c << '\n';
}
}
}
For a variable N, obviously we need a different strategy. And, it turns out, it needs an incredibly different strategy. This is based on DaMachk's answer, of using recursion to generate subsequent letters
template<class func_type>
void generate(std::string& word, int length, const func_type& func) {
for(char i='a'; i<='z'; ++i) {
bool used = false;
for(char c : word) {
if (c==i) {
used = true;
break;
}
}
if (used) continue;
word.push_back(i);
if (length==1) func(word);
else generate(word, length-1, func);
word.pop_back();
}
}
template<class func_type>
void generate(int length, const func_type& func) {
std::string word;
generate(word, length, func);
}
You can see it here
I also made an unrolled version, which turned out to be incredibly complicated, but is significantly faster. I have two helper functions: I have a function to "find the next letter" (called next_unused) which increases the letter at an index to the next unused letter, or returns false if it cannot. The third function, reset_range "resets" a range of letters from a given index to the end of the string to the first unused letter it can. First we use reset_range to find the first string. To find subsequent strings, we call next_unused on the last letter, and if that fails, the second to last letter, and if that fails the third to last letter, etc. When we find a letter we can properly increase, we then "reset" all the letters to the right of that to the smallest unused values. If we get all the way to the first letter and it cannot be increased, then we've reached the end, and we stop. The code is frightening, but it's the best I could figure out.
bool next_unused(char& dest, char begin, bool* used) {
used[dest] = false;
dest = 0;
if (begin > 'Z') return false;
while(used[begin]) {
if (++begin > 'Z')
return false;
}
dest = begin;
used[begin] = true;
return true;
}
void reset_range(std::string& word, int begin, bool* used) {
int count = word.size()-begin;
for(int i=0; i<count; ++i)
assert(next_unused(word[i+begin], 'A'+i, used));
}
template<class func_type>
void doit(int n, func_type func) {
bool used['Z'+1] = {};
std::string word(n, '\0');
reset_range(word, 0, used);
for(;;) {
func(word);
//find next word
int index = word.size()-1;
while(next_unused(word[index], word[index]+1, used) == false) {
if (--index < 0)
return; //no more permutations
}
reset_range(word, index+1, used);
}
}
Here it is at work.
And here it is running in a quarter of the time as the simple one
I was doing a similar thing in powershell. Generating all the possible combinations of 9 symbols. After a bit of trial and error this is what I came up with.
$S1=New-Object System.Collections.ArrayList
$S1.Add("a")
$S1.Add("b")
$S1.Add("c")
$S1.Add("d")
$S1.Add("e")
$S1.Add("f")
$S1.Add("g")
$S1.Add("h")
$S1.Add("i")
$S1 | % {$a = $_
$S2 = $S1.Clone()
$S2.Remove($_)
$S2 | % {$b = $_
$S3 = $S2.Clone()
$S3.Remove($_)
$S3 | % {$c = $_
$S4 = $S2.Clone()
$S4.Remove($_)
$S4 | % {$d = $_
$S5 = $S4.Clone()
$S5.Remove($_)
$S5 | % {$e = $_
$S6 = $S5.Clone()
$S6.Remove($_)
$S6 | % {$f = $_
$S7 = $S6.Clone()
$S7.Remove($_)
$S7 | % {$g = $_
$S8 = $S7.Clone()
$S8.Remove($_)
$S8 | % {$h = $_
$S9 = $S8.Clone()
$S9.Remove($_)
$S9 | % {$i = $_
($a+$b+$c+$d+$e+$f+$g+$h+$i)
}
}
}
}
}
}
}
}
}