I have a Haskell function which reports a long error message. Although I can write this message in one line, I want to break it into two or more e.g.
foo a b | a > b = a
| a == b = b
| otherwise = error "Blah blah blah blah in this line and
some more blah in this line also."
GHCi does not compile it. Any suggestion? A casual googleing did not produce any answer.
You can use ghc's multi-line string syntax for this:
foo a b | a > b = a
| a == b = b
| otherwise = error "Blah blah blah blah in this line and \
\some more blah in this line also."
For errors it doesn't matter much, but in other contexts it can be more efficient than concatenating strings.
you can just concatenate the strings:
foo a b | a > b = a
| a == b = b
| otherwise = error ("Blah blah blah blah in this line and"
++ " some more blah in this line also.")
this works for me
Related
I have a text file with text like this:
{"id":2705,"status":"Analyze","severity":"Critical",Blah Blah ... "file":"/home/foo.c","message":"Message is...","url":"http://aaa..."}
{"id":2706,"status":"Fix","severity":"Low",Blah Blah ... "file":"/home/foo1.h","message":"Message2 is...","url":"http://bbb..."}
I would like to have bash script, that reads file, and for each line use all pairs of data as variables (for example id=2705, status="Analyze"...) and echo them.
awk 'BEGIN{RS=",";FS=":";OFS="="}{$1=$1;gsub("}|{|\"","")}1' infile
id=2705
status=Analyze
severity=Critical
Blah Blah ... file=/home/foo.c
message=Message is...
url=http=//aaa...
id=2706
status=Fix
severity=Low
Blah Blah ... file=/home/foo1.h
message=Message2 is...
url=http=//bbb...
I have data structures as such:
data IfTree = If Expr Statement IfTree | Else Statement | EndIf
data Statement = IfStatement IfTree
What is want is to make it impossible to do any of these combinations:
IfStatement $ Else ...
IfStatement $ EndIf
An IfStatement should only be able to take an If.
I am aware that I can hide the data constructors and only expose functions that compose them behind the scenes, but I want to limit this at the data type.
Update:
What I was trying to do was clunky. Thanks to the excellent answers and comments, a MUCH better way of handling this was given:
data Statement = If Expr Statement (Maybe Statement) | ...
or even:
data Stat = IfStat Expr Stat | IfElseStat Expr Stat Stat | …
This would be the traditional way of doing it:
data Stat = IfStat Expr Stat (Maybe Stat) | BarStat | BazStat | …
data Expr = FooExpr | …
-- if (foo) bar;
IfStat FooExpr BarStat Nothing
-- if (foo) bar; else baz;
IfStat FooExpr BarStat (Just BazStat)
The idea is to encode the grammar of your language as a data type, or at least the important bits. Else and EndIf don’t make sense outside of an If, so you don’t actually need to represent them.
You can inline the Maybe into the statement data type:
data Stat = IfStat Expr Stat | IfElseStat Expr Stat Stat | …
Or, if it makes sense for your language, you can add a representation for empty statements:
data Stat = IfStat Expr Stat Stat | EmptyStat | …
-- if (foo) bar;
-- if (foo) bar; else;
IfStat FooExpr BarStat EmptyStat
-- if (foo) bar; else baz;
IfStat FooExpr BarStat BazStat
However, normalising things like this can be problematic if you want exact pretty-printing later on.
Block statements can be handled similarly:
data Stat = … | BlockStat [Stat] | …
-- if (foo) { bar; baz; }
IfStat FooExpr (BlockStat [BarStat, BazStat]) EmptyStat
The problem is that an If isn't just an Else. You should define something like
data If = IfNoElse Expr Statement | IfElse Expr Statement Statement
data Statement = If If | While | ...
assuming that we have a file containing the following:
chapter 1 blah blah
blah num blah num
num blah num blah
...
blah num
chapter 2 blah blah
and we want to grep this file so we take the lines
from chapter 1 blah blah to blah num
(the line before the next chapter).
The only things we know are
the stating string chapter 1 blah blah
somewhere after that there is another line starting with chapter
a dummy way to do this is
grep -A <num> -i "chapter 1" <file>
with large enough <num> so the whole chapter will be in it.
sed -ne '/^chapter 1/,/^chapter/{/^chapter/d;p}' file
This is easy to do with awk
awk '/chapter/ {f=0} /chapter 1/ {f=1} f' file
chapter 1 blah blah
blah num blah num
num blah num blah
...
blah num
It will print the line if flag f is true.
The chapter 1 and next chapter to changes the flag.
You can use range with awk but its less flexible if you have other stuff to test.
awk '/chapter 1/,/chapter [^1]/ {if (!/chapter [^1]/) print}' file
chapter 1 blah blah
blah num blah num
num blah num blah
...
blah num
You could do this through grep itself also but you need to enable Perl-regexp parameter P and z.
$ grep -oPz '^chapter 1[\s\S]*?(?=\nchapter)' file
chapter 1 blah blah
blah num blah num
num blah num blah
...
blah num
[\s\S]*? will do a non-greedy match of zero or more characters until the line which has the string chapter at the start is reached.
From man grep
-z, --null-data a data line ends in 0 byte, not newline
-P, --perl-regexp PATTERN is a Perl regular expression
-o, --only-matching show only the part of a line matching PATTERN
I have a file called names.xml
That looks like the below:
NAME="Stacey" SURNAME="Ford"
blah blah blah
NAME="Stacey" SURNAME="Ford"
blah blah blah
I need to find all occurrences of NAME=" and with the "" quotes I need to replace the name with another value.
So the output needs to look like this:
NAME="Jack" SURNAME="Ford"
blah blah blah
NAME="Jack" SURNAME="Ford"
blah blah blah
I am using: sed 's/NAME=".*"/NAME="Jack"/g' names.xml
But this is the result it gives me:
NAME="Jack"
blah blah blah
NAME="Jack"
blah blah blah
It is looking at everything up until the last " on SURNAME.
Your time and assistance is greatly appreciated.
You need to use a negated character class [^"]* which matches any character but not of " zero or more times. .* in your regex is greedy by default, it eats all the characters upto the last " double quotes. So that only it matches Stacey and upto the last Ford. And also you must need to add a word boundary \b before the NAME, so that it won't match the string NAME in SURNAME . \b matches between a word character and a non-word character.
sed 's/\bNAME="[^"]*"/NAME="Jack"/g' names.xml
Here is an awk version:
awk -F\" -vOFS=\" '$1~/NAME=/ {$2="Jack"}1' file
NAME="Jack" SURNAME="Ford"
blah blah blah
NAME="Jack" SURNAME="Ford"
blah blah blah
Use " as field separator. If field 1 contains NAME= replace filed 2 with Jack and print it.
I've a very long file as follows.
Input file :-
Text Point
Blah
Blah
Blah
Blah
Blah
Blah
String
Blah
Blah
Blah
Blah
Blah
Blah
Text Point
Blah
Blah
Blah
Blah
Blah
Blah
Text Point
String
Blah
Blah
Text Point
Blah
Blah
Blah
String
Blah
Blah
Blah
Text Point
Blah
Blah
String
Blah
After each Occurrence of a 'Text Point', and before the next occurrence, I expect 'String' to occur at maximum once. I've to extract string if it is occurring between Two consecutive 'Text point's to a output file Or I've to put a dash if it is not occurring.
In this case, I need a output like this
String
-
String
String
String
I tried using following command
sed -n '/Text point/{:a;N;/^\n/s/^\n//;/Text point/{p;s/.*//;};ba};' $1 | grep "String" >> Outfile
But the problem with this is when string isn't found it will not append anything to outfile.
So please help me out with the code. Thanks.
I have a solution with perl
use strict;
use warnings;
$/="Text Point";
while(<>) {
if(/String/m) {
print "String \n" ;
}
else{
print "- \n" ;
}
}
awk '/^Text Point/{print p; p="-" } /String/{ p=$0} END{print p}' input
Using a perl one-liner
perl -0777 -ne 'print /(.*String.*\n)/ ? $1 : "-\n" for split /(?=Text Point)/' file
Explanation:
Switches:
-0777: Slurp entire file
-n: Creates a while(<>){...} loop for each “line” in your input file.
-e: Tells perl to execute the code on command line.