How to operate on part of line only - sed

How do I make sed operate on specific parts of a line only? And, on the contrary, how do I make sed not work on specific parts of a line?
Examples:
"A a A a ( A a ) A ( a A ) a"
How do I, for instance, replace all the As with Ts only between the ( and ) to obtain:
"A a A a ( T a ) A ( a T ) a"
And given next example input:
"F f F f ( F f ) F ( f F ) f"
How do I, for instance, replace all the Fs with Xs but not between the ( and ) to
obtain:
"X f X f ( F f ) X ( f F ) f"
I searched Google but found nothing usable. I guess it's a general question about sed. The problem is reducible to general sed "templates", I hope.
having FROM and TO then operate between them only (on all occurrences on given line)
having FROM and TO operate anywhere else than between them...
special case when FROM and TO are the same (between " and " or "FOO" and "FOO" etc.)
for both 1. and 2.
It should work with any operation, not just substitution, but also with printing etc., like printing everything between strings "FOO" and "BAR" in string.
"1 2 3 BAR a b c FOO d e f BAR g a h FOO i j k BAR l m n FOO o p q"
The result will be
" d e f i j k "
So, general examples on how to do it would be highly appreciated. It also seems that this question is quite common, but no good howto is found on the Google yet. I also guess this
would be quite challenging to answer. Please, also do no give any hints on how to do it
using Perl, AWK or whatever else than sed. This question is really a sed-only question.

Divide and conquer.
Insert newlines to separate the segments then use the newlines, line beginning (^), line ending ($) and delimiter characters (parentheses in this case) as anchors and loop. The added newlines are removed at the end.
$ echo "A a A a ( A a ) A ( a A ) a" |
sed 's/([^)]*)/\n&/g;
:a;
s/\(\n([^)]*\)A\([^)]*)\)/\1T\2/;
ta;
s/\n//g'
A a A a ( T a ) A ( a T ) a
$ echo "F f F f ( F f ) F ( f F ) f" |
sed 's/(/\n(/g;
s/)/)\n/g;
:a;
s/\([^(]*\)F\([^)]*\(\n\|$\)\)/\1X\2/g;
ta;
s/\n//g'
X f X f ( F f ) X ( f F ) f
$ echo "1 2 3 BAR a b c FOO d e f BAR g a h FOO i j k BAR l m n FOO o p q" |
sed 's/^/BAR/;
s/$/FOO/;
s/FOO/&\n/g;
s/BAR/\n&/g;
s/BAR[^\n]*\n//g;
s/[^\n]*FOO\n//g;
s/\n//g'
d e f i j k

This might work for you (GNU sed):
sed ':a;s/\(([^)]*\)A/\1T/;ta' file # for case 1
sed ':a;s/\(([^)]*\)F/\1\n/;ta;y/F\n/TF/' file # for case 2
For case 1 use a loop to substitute A's inside brackets to T's.
For case 2 use the same as above to change F's inside brackets to newlines, then translate F's and newlines to X's and F's respectively.
Case 3 is a little more involved but can be done in 2 substitute commands:
sed -r 's/FOO|BAR/\n&/g;s/[^\n]*(\nBAR[^\n]*)*(\nFOO([^\n]*)\nBAR)?(\nFOO[^\n]*$)?/\3/g' file
First prefix each FOO and BAR strings with newlines. Then look for all combinations of FOO and BAR and only keep the strings between FOO and BAR. The newlines allow the use of the negative class to simplify the procedure.

Related

How can I do pattern matching in the purescript repl

I have the following in the repl
> :t foo
Tuple Int Int
I made an attempt to do pattern matching against foo
> (Tuple q w) = foo
Unexpected token '=' at line 1, column 13
So my question is: "What's the proper syntax to do pattern matching in the repl?"
Well, you should be able the following way:
(q /\ w) = foo

Minizinc nested output loop

I am trying to write an output statement with nested loops, and non-trivial output at the outer levels. If Minizinc had a top level for command, I would do something like
for (f in Foo) (
output(["Foo: ", f])
for (b in Bar) (
for (q in Quz) (
output([myArray[f,b,q], " "]);
)
output(["\n"]);
)
output(["\n"]);
)
so that if
myArray = [[[1,2], [3,4]], [[5,6], [7,8]]];
it would output
Foo: 1
1 2
3 4
Foo: 2
5 6
7 8
I think I can do this with something like
output(if (b = 1 /\ q = 1) then "Foo: " ++ show(f) else "" endif ++
show(myArray[f,b,q] ++ " " ++
if (<maximum q>) <newline> ++
if (<maximum q and maximum b>) <newline>
| f in Foo, b in Bar, q in Quz);
but that seems awkward (and my first attempt did not work).
I saw Minizinc nested for loop which is different, because all of the output is inside the inner-most loop. I want output in the outer loops as well.
I think a slightly clearer version of the accepted answer would be
output [
"Foo: \(f)\n"
++ concat(
concat([show(myArray[f,b,q]) ++ " " | q in Quz])
++ "\n"
| b in Bar])
++ "\n"
| f in Foo];
This avoids the if/then/else construct, and makes it clear that we are adding additional output before/after each inner loop.
As you already said: MiniZinc output statements can be a little awkward. The output statement consists of the keyword output followed by an array of strings. In a lot of cases we would like to use for-loop, but in a declarative language like MiniZinc those kind of control-flow structure are not available.
You already offered the solution though: Array Comprehensions! It seems you were almost there, but your syntax was a little off and you might not be understanding how they actually work. An array comprehension is similar to a for-loop in that it does iterate over all values in a set. However, it is different in that it doesn't just execute the statements in the loop, but evaluates them and all results need to be of the same type, string in this case.
The output statement you are writing could be written like this:
output [
"Foo: \(f)\n"
++ concat(["\(myArray[f,b,q])"
++ if q == max(Quz
then "\n"
else " "
endif
|b in Bar, q in Quz])
++ "\n"
| f in Foo];

How are these boolean expressions (truth tables) equivalent?

I am trying to better understand boolean equivalence but this example has me a little stuck.
I am referring to this website: http://chortle.ccsu.edu/java5/Notes/chap40B/ch40B_9.html
It makes sense, but doesn't at the same time... it says that they are equivalent, but the true/false values don't add up/align in a way that makes them out to be equivalent as the table shows they are. Could someone explain this to me?
!(A && B) <-- first expression
(C || D) <-- second expression
The last columns refers to the equivalency of the two expressions, which yes, they are equivalent according to the table. However, I just don't get how the two expressions are equivalent. If A = F, B = F --> T, wouldn't C = F, D = F --> T as well?
A B C D
--------------------
F F T T T
F T T F T
T F F T T
T T F F F
You are confusing yourself when trying to reduce it from the actual expression to single letter variables. On referring the actual link, it would appear that the variables you use can be mapped to the original expressions as follows:
A = speed > 2000
B = memory > 512
C = speed <= 2000
D = memory <= 512
If you look at it, C equals !A and D equals !B. So the expression (C || D) is effectively !((!A) || (!B)). By De Morgan's Law, that is the same as !(A && B).
This table is explaining that !(A && B) is equivalent to !A || !B. The columns C and D appear to be defined as C = !A and D = !B. The last column is C || D
So A = F, B = F certainly implies !(A && B). In this case C = D = T, and so also C || D = T.

How can I interchange the values of a number of columns depending on a key using awk or perl?

Is there a simple way of interchanging columns in a tabulated file like this?
The keys would be the first and third column but the second column should be appended to the first key and the 4th column to the third.
The swap between the columns depends on the existence of the first key(1st col) against the second key(3rd column).
A B C D
E F A B
H I A G
J K L M
N J Q K
The desired output would be like this:
A B C D
A B E F
A G H I
J K L M
N J Q K
this works for you: I could make it in a "one-liner", but I think that I paste in this way is easier to read.
awk 'NR==1{a[$1];print;next;}!($1 in a){
r="";h=$1;
for(i=2;i<=NF;i++)
if($i in a){
for(m=i;m<=NF;m++)
r=(r?r" ":"")$m
break;
}else{
h=h" "$i
}
$0=(r?r" ":"")h;
}1' file
test with your data:
kent$ echo "A B C D
E F A B
H I A G
J K L M
N J Q K"|awk 'NR==1{a[$1];print;next;}!($1 in a){
r="";h=$1;
for(i=2;i<=NF;i++)
if($i in a){
for(m=i;m<=NF;m++)
r=(r?r" ":"")$m
break;
}else{
h=h" "$i
}
$0=(r?r" ":"")h;
}1'
A B C D
A B E F
A G H I
J K L M
N J Q K
Here is a simpler solution using Perl. This will fail if two odd columns on the same line have the same contents, e.g.
C D C A # Would print out "C A" only
Otherwise, we can use the hash data structure that provides easy manipulation of key-value pairs.
perl -ple'%h=split;$_=join" ",map{$_=>$h{$_}}sort keys %h'
Example Usage:
$ perl -ple'%h=split;$_=join" ",map{$_=>$h{$_}}sort keys %h' <<'END'
A B C D
E F A B
H I A G
J K L M
N J Q K
END
Output:
A B C D
A B E F
A G H I
J K L M
N J Q K
Without that weakness, I would write it like
perl -pale'#f=();push#f,[splice#F,0,2]while#F;$_=join" ",map#$_,sort{$a->[0]cmp$b->[0]}#f'
which essentially does a Schwartzian Transform.
Explanations
1st solution:
The option -l handles line endings for us. -p loops over all input lines (putting them in $_) and prints out the contents of $_ after each iteration.
A hash is constructed as a list of alternating keys and values. The split function without options splits the contents of $_ on whitespace, and returns a list which we assign to the hash %h. Duplicate keys are removed; only the last occurrence is set.
We sort the keys alphabetically. map takes each key and transforms the list of keys into a list of alternating keys and values, but in the correct order this time.
We join this list of strings via a single space and assign it to $_, which is printed because of -p.
2nd solution:
The -a options autosplits the $_ into the #F array. We take the first two elements of #F with splice, put them into an anonymous arrayref, and push this arrayref into #f array. We repeat until no elems are left. This pairs the contents of #F, and isn't bothered by duplicates.
We sort the arrayrefs in #f by their first element alphabetically, and flatten the resulting order with map. After that, we join the strings as before.

PowerShell: How To Use Standard Output In Place of Filename

I'm writing a C# class that runs a Process (REG) to export registry keys. REG requires that you specify a filename to export to but I would rather have the output of REG directed to the standard output so I can capture it directly in my C# code (using Process.StandardOutput). Is there a way in PowerShell to specify the standard output as the filename?
If you have to use the REG program (rather than use PowerShell to query/dump the registry - or even just do it in the C# program itself), Probably the best you are going to get is to allow it to dump out to a temporary file, then pipe the contents of the file back to standard out and capture it in your C# program that way:
$guid = [Guid]::NewGuid().ToString("N")
REG EXPORT HKCU\Software\Microsoft\Windows "$env:temp\$guid" | Out-Null
Get-Content "$env:temp\$guid"
Remove-Item "$env:temp\$guid"
In case you were not aware: Using PowerShell, you can navigate the registry as though it were part of the file system. Perhaps this is helpful in some other regard?
cd HKCU:\Software\Microsoft\Windows
dir
Just use 'CONOUT$' as the file name (as pojnted out in comments, this only works on Windows XP):
PS C:\> reg export HKLM\SOFTWARE\FileZilla 'CONOUT$'
■W i n d o w s R e g i s t r y E d i t o r V e r s i o n 5 . 0 0
[ H K E Y _ L O C A L _ M A C H I N E \ S O F T W A R E \ F i l e Z i l l a ]
" I n s t a l l _ D i r " = " C : \ \ P r o g r a m F i l e s \ \ F i l e Z i l l a "
" R u n i n S e c u r e M o d e " = " 0 "
" U s e R e g i s t r y " = " 0 "
" L a n g u a g e " = " E n g l i s h "
There are some UNICODE encoding issues in the output shown here, but you should be able to handle that in the buffer when you parse it.