How to search in a file by field - if-statement

I have this input:
AB1 oo1 FE11 aq
cd7 pp9 xw11 as
md1 Al1 as101 sd
ak5 AB1 aw1 sd
ci6 QB7 cr12 sw
do0 RB1 AB1 sq
and need this output: AB1 in the field 1 and 2 and 3
I tried this but there is something wrong:
awk '{ for (i=1;i<NF;i++) { if ($i ~/AB1/) } print $i }' file name
Is thre any thing wrong with my code? Pleaase, tell me and if you have better cods show it to me.
Thank you all

You have some syntax errors in your code:
awk '{ for (i=1;i<NF;i++) { if ($i ~/AB1/) } print $i }' file name
the closing } in if ($i ~/AB1/) } is a mistake, the if needs a command there, and you need a closing } to match the very first {, like this:
awk '{ for (i=1;i<NF;i++) { if ($i ~/AB1/) print $i }}' file name
with this syntax error corrected, the output is:
AB1
AB1
AB1
To print the number of the field with the value AB1, I would write like this:
$ awk '{ for (i=1; i<NF; ++i) if ($i == "AB1") print i }' file
1
2
3

corrected line of code
awk '{ for (i=1;i<NF;i++) { if ($i ~/AB1/) print $i }}' file name
original
awk '{ for (i=1;i<NF;i++) { if ($i ~/AB1/) } print $i }' file name
the problem was bracket u placed it at wrong place

If you want "string in the fields: n n n":
awk -v string="AB1" '
{ if ( maxNF < NF ) { maxNF = NF ; } }
$0~string { we_found_it=1 ;
for (i=1; i<=NF; i++)
{ if ( $i ~ string ) { found_in[i]++ ; }
}
}
END { if ( we_found_it == 1 )
{ printf "%s in the fields: ", string ;
for (i=1; i<=maxNF ; i++)
{ if (found_in[i]>0)
{ printf "%s ", i ;
}
}
}
else
{ printf "%s was NOT found in any fields.", string ;
}
} '
This matches the string anywhere in the field (ex: "...AB1..." matches)
If you prefer an exact match:
awk -v string="AB1" '
{ if ( maxNF < NF ) { maxNF = NF ; } }
$0~string { for (i=1; i<=NF; i++)
{ if ( $i == string )
{ we_found_it=1 ;
found_in[i]++ ;
}
}
}
END { if ( we_found_it == 1 )
{ printf "%s in the fields: ", string ;
for (i=1; i<=maxNF ; i++)
{ if (found_in[i]>0)
{ printf "%s ", i ;
}
}
}
else
{ printf "%s was NOT found in any fields.", string ;
}
} '
That one matches exactly (ie: "AB1" matches "AB1", but not "...AB1kkk")

Related

Match a For Loop Using a 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.

The way to strip newline characters

Let's say we have a long string with multiple newline characters:
char const* some_text = "part1\n\npart2\npart3";
Now the task is to replace all '\n' characters with spaces if it appears only once between text parts, and at the same time leave all '\n' characters if it appears more than once. In other words:
"123\n456" => "123 456"
"123\n\n456" => "123\n\n456"
"123\n\n456\n789" => "123\n\n456 789"
What is the best way to do this?
The following regular expression detects single occurrences of newlines:
([^\n]|^)\n([^\n]|$)
|-------|
no newline before
(either other character or beginning of string)
|--|
newline
|--------|
no newline after
(either other character or end of string)
You can use that regular expression in std::regex_replace in order to replace those single newlines by spaces (and keeping the matched character before and after the newline by adding $1 and $2):
std::string testString("\n123\n\n456\n789");
std::regex e("([^\n]|^)\n([^\n]|$)");
std::cout << std::regex_replace(testString, e, "$1 $2") << std::endl;
Since it was tagged as C++, I'll treat it as such. Obviously this could be solved with a regex but it's equally trivial enough (as described) not to require one.
std::string s = "your\n\nstring\nhere\n";
size_t n = -1, len = s.length();
while ((n = s.find('\n', n+1)) != std::string::npos)
if ((n == 0 && s[n+1] != '\n') || (n == len && s[n-1] != '\n') ||
(n != 0 && n != len && s[n-1] != '\n' && s[n+1] != '\n'))
s[n] = ' ';
This function may works for your case, just manually check and replace single \n with space. There may have better option like regex_replace.
void rep(char ch[])
{
int cnt = 0;
int i;
for(i=0; ch[i]!='\0'; i++)
{
if(ch[i]=='\n')
cnt++;
else if(cnt==1)
{
ch[i-1]=' ';
cnt=0;
}
else
cnt=0;
}
if(cnt==1)
ch[i-1]=' ';
}

c++ splitting a string and getting the part coming after whitespace

I need to do a string splitting such that If I have a string like below
string foo="thisIsThe Test Input";
I need to get the part coming after the multiple or single withspace. In this case I need to get "Test Input". I know that I can get the first part by :
int index=foo.find(' ');
string subString=foo.substr(0,index);
But I dont know how could I do what I want. Is there anyone to help me ?
std::find_first_not_of accepts a position argument which indicates where to start searching. So use that to find the first non-space, starting at the first space.
int index=foo.find(' ');
index=foo.find_first_not_of(' ', index);
string subString=foo.substr(index);
You can also copy to a new string char by char eliminating any spaces too.
It will make it easier to use foo.find(' ');
Eliminate all whitespace
string foo = "thisIsThe Test Input";
string bar[100];
for (int i = 0; i < foo.length(); i++)
{
if (foo[i] != ' ')
bar[i] = foo[i];
}
for (int i = 0; i < sizeof(bar) / sizeof(bar[i]); i++)
cout << bar[i];
Keep one space between each term:
string foo = "thisIsThe Test Input";
string bar[100];
for (int i = 0; i < foo.length(); i++)
{
if (foo[i] != ' ')
bar[i] = foo[i];
else if (foo[i + 1] != ' ' && foo[i] == ' ')
bar[i] = ' ';
}
for (int i = 0; i < sizeof(bar)/sizeof(bar[i]); i++)
cout << bar[i];

Porting XOR encryption code to PHP

I usually find my answer here somewhere, but I've been unable to find the solution from the existing questions. I apologize if I misssed an answer elsewhere..
This is my C++ code :
char key[4] = "abc";
for (int temp = 0; temp < original.size(); temp++){
encrypted += original[temp] ^ (int(key) + temp) % 255;
}
cout << int(key) << endl;
cout << "Encrypted data = " << encrypted << endl;
for (int temp = 0; temp < original.size(); temp++){
unencrypted += encrypted[temp] ^ (int(key) + temp) % 255;
}
cout << "Unencrypted data = " << unencrypted << endl;
Which returns a long string of random characters (e.g. ♧).
And my attempt at translating, as to my understanding, the XOR encryption to PHP:
<?php
$input = "ONEWORD";
$encrypted = "";
$unencrypted = "";
$key = "abc";
$ascii = NULL;
for ($i = 0; $i < strlen($string); $i++)
{
$ascii += ord($string[$i]);
}
for($i = 0; $i < sizeof($input); $i++)
{
$encrypted+= $input[$i] ^ ($ascii + $i) % 255;
}
echo($encrypted);
echo(ord($key));
for($i = 0; $i < sizeof($input); $i++)
{
$unencrypted+= $encrypted[$i] ^ ($ascii + $i) % 255;
}
echo($unencrypted);
?>
While this returns a simple 0970.
I'm not quite sure where I went wrong, can anyone lead me in the right direction?
Thanks
This line in your C++ code is bogus:
encrypted += original[temp] ^ (int(key) + temp) % 255;
This doesn't do what you think it does. int(key) casts key to int. In this context key will decay to a pointer, so you're not actually getting the key at all, you're getting an integer representation of the pointer to the key.
What you likely want is this:
encrypted += char(original[temp] ^ key[temp % 3]);
That will XOR the first character of the string with the first character of the key, the second character of the string with the second character of the key, and third character of the string with the third character of the key. Thereafter, it'll cycle through the three characters in the key, applying them to each character of the input in-turn.
You need to make a similar change to your decryption code:
unencrypted += char(encrypted[temp] ^ key[temp % 3]);
In PHP, to work with individual character values, you need to use the ord operator to convert the characters to integers, and the chr operator to convert the integers back to characters.
$encrypted += chr( ord( $input[$i] ) ^ ord( $key[$i % 3] ) );
And likewise for decryption:
$decrypted += chr( ord( $encrypted[$i] ) ^ ord( $key[$i % 3] ) );
Firstly, your C++ code....
int(key) is probably not doing what you expected. It's demoting the key array to a pointer and converting the pointer value to an integer. Perhaps you meant to do int(*(int*)key).
If you actually intended it to work like the code you wrote in PHP, then you'll have to modify the key calculation:
int keyval = 0;
for( unsigned char *p = key; *p; p++ ) keyval += *p;
It's not a very robust key, however. It will be the same value regardless of what order the key's characters appear.
Now to the PHP.
You should use ord to get the character value, then do the calculation, then use chr to convert back to a character before appending to your string:
$encrypted += chr( ord($input[$i]) ^ ($ascii + $i) % 255 );
One final observation... In both your code examples, I wonder if you meant to modulo by 256, not 255.

In fish shell, how can I put two conditions in an if statement?

What I want to do using bash:
> if true; then echo y; else echo n; fi
y
> if false; then echo y; else echo n; fi
n
> if false || true; then echo y; else echo n; fi
y
Now trying with fish:
> if true; echo y; else; echo n; end
y
> if false; echo y; else; echo n; end
n
# Here 'or true' are just two arguments for false
> if false or true; echo y; else; echo n; end
n
# Here 'or true;' is a command inside the if
> if false; or true; echo y; else; echo n; end
n
# Can't use command substitution instead of a command
> if (false; or true); echo y; else; echo n; end
fish: Illegal command name “(false; or true)”
How can I have two conditions in an if?
Two other approaches:
Approach one:
if begin false; or true; end
echo y
else
echo n
end
Approach two:
false; or true
and echo y
or echo n
This way works, but it is an ugly hack:
> if test (true; and echo y); echo y; else; echo n; end
y
> if test (false; and echo y); echo y; else; echo n; end
n
> if test (false; or true; and echo y); echo y; else; echo n; end
y
I sincerely hope for better answers.
Since fish 2.3b1, one can directly chain commands in the if condition with and/or. The begin ... end is not necessary anymore. The official docs were updated in May 2016.
So now this works as expected:
> if false; or true; echo y; else; echo n; end
y