i need to replace multiple characters by single character
RETURN LOWER(REPLACE("ranchod-das-chanchad-240190---Funshuk--Wangdu",'--', '-'))
is there any regex to do this
for neo4j 2.2.2
There's no function similar to REPLACE taking a regex as a parameter.
Since you're using Neo4j 2.2, you can't implement it as a procedure either.
The only way to do it is by splitting and joining (using a combination of reduce and substring):
RETURN substring(reduce(s = '', e IN filter(e IN split('ranchod-das-chanchad-240190---Funshuk--Wangdu', '-') WHERE e <> '') | s + '-' + e), 1);
It can be easier to read if you decompose it:
WITH split('ranchod-das-chanchad-240190---Funshuk--Wangdu', '-') AS elems
WITH filter(e IN elems WHERE e <> '') AS elems
RETURN substring(reduce(s = '', e IN elems | s + '-' + e), 1);
Related
I'm looking at reducers.
There is a nice example in the Tutor for counting words:
(0 | it + 1 | /\w+/ := S)
where S is some longer string with several words. The reducer returns the count of such words.
I was wondering how to capture the matched substring and use it in the accumulating expression, something like
("" | it + e | str e ... /\w+/ := S)
so that the result would be the concatenation of all matched substrings.
Any idea?
Yes, the capture syntax is with the <name:regex> notation:
("" | it + e | /<e:\w+>/ := S)
rascal>S ="Jabberwocky by Lewis Carroll";
str: "Jabberwocky by Lewis Carroll"
rascal>("" | "<it>,<e>" | /<e:\w+>/ := S)[1..]
str: "Jabberwocky,by,Lewis,Carroll"
or use the for-template syntax instead of a reducer expression:
rascal>x = "<for (/<e:\w+>/ := S) {><e>;
>>>>>>> '<}>";
str: "Jabberwocky;\nby;\nLewis;\nCarroll;\n"
rascal>import IO;
ok
rascal>println(x)
Jabberwocky;
by;
Lewis;
Carroll;
ok
rascal>
My task is to write grammar for custom query language, where users can write some basic queries.
My grammar so far:
grammar EAQL;
prog: cond;
cond: cond logical_operator cond | elexpr comparison_operator VALUE;
elexpr: ELSTEREOTYPE '.' eattribute;
conexpr: CSTEREOTYPE '.' cattribute;
eattribute: 'Name' | 'Path' | 'GUID' | conexpr;
cattribute: 'Name' | 'GUID' | elexpr;
VALUE: QUOTATION ( ~([QUOTATION]) | ~('\n'))+ QUOTATION;
ELSTEREOTYPE: 'EG_ApplicationComponent' | 'EG_ApplicationFunction';
CSTEREOTYPE: 'EG_Flow';
SPACE: ' ';
QUOTATION: '"';
EOL: '\n';
WS : (' ' | '\t')+ -> channel(HIDDEN);
AND: 'AND';
OR: 'OR';
logical_operator: AND | OR;
EQUALS: '=';
GREATER_THAN: '>';
SMALLER_THAN: '<';
comparison_operator: GREATER_THAN | SMALLER_THAN | EQUALS;
When i try to parse this string
EG_ApplicationComponent.Name= "name1" AND EG_ApplicationFunction.Name="name2"
ANTLR will create following children in tree:
'EG_ApplicationComponent'
'.'
'Name'
'='
'"name1" AND EG_ApplicationFunction.Name= "name2"'
I am absolute beginner in creating parsers, but i still do not understand why it does greedy matching until end of string in VALUE, when I specified that matching should end when QUOTATION is found. I expect, that if would match 'name1' as VALUE in first branch of tree and then create another branch with EG_ApplicationFunction.Name= "name2" parsed as previous branch.
This would be my expected result:
'EG_ApplicationComponent'
'.'
'Name'
'='
'"name1"'
AND
EG_ApplicationFunction
'.'
'Name'
'='
'"name2"'
~[QUOTATION] matches any character other than Q, U, O, T, A, T, I, O and N. What you need to do is ~["].
Your VALUE rule could look like this:
VALUE
: QUOTATION ~["\r\n]* QUOTATION
;
I would like to reduce a list into a string to adhere to a specific output format which requires a pipe ( '|' ) between the elements. I do it as follows:
WITH ["three", "two", "one"] AS a RETURN reduce(acc=head(a), s in tail(a) | acc + "|" + s)
My issue arises by the fact that the array has the wrong order: You see that it "counts" descending while I'd like to have it ascending (in my production environment the array is an intermediate result of a graph query, of course).
So I thought I would just do
WITH ["three", "two", "one"] AS a RETURN reduce(acc=head(a), s in REVERSE(tail(a)) | acc + "|" + s)
Unfortunately, reverse seems to return a collection of some generic type (any) which is not accepted by the string concatenation operator:
Type mismatch: expected Float, Integer, String or List<String> but was Any (line 1, column 98 (offset: 97))
"WITH ["three", "two", "one"] AS a RETURN reduce(acc=head(a), s in reverse(tail(a)) | acc + "|" + s)"
^
Thus I'd like to convert the 's' to a string via toString. This function, however, will only accept integer, float or boolean values and not any.
What can I do? I would also accept a solution without the conversion. I just want to be able reduce a reversed collections of strings into a single string.
Thank you!
You can avoid using the REVERSE() function by simply reversing the order in which you concatenate (i.e., using s + "|" + acc instead of acc + "|" + s):
WITH ["three", "two", "one"] AS a
RETURN REDUCE(acc=HEAD(a), s in TAIL(a) | s + "|" + acc )
function expandVars(tmpl,t)
return (tmpl:gsub('%$([%a ][%w ]+)', t)) end
local sentence = expandVars("The $adj $char1 looks at you and says, $name, you are $result", {adj="glorious", name="Jayant", result="the Overlord", char1="King"})
print(sentence)
The above code work only when I have ',' after the variable name like, in above sentence it work for $ name and $ result but not for $adj and $char1, Why is that ?
Problem:
Your pattern [%a ][%w ]+ means a letter or space, followed by at least one letter or number or space. Since regexp is greedy, it will try to match as large a sequence as possible, and the match will include the space:
function expandVars(tmpl,t)
return string.gsub(tmpl, '%$([%a ][%w ]+)', t)
end
local sentence = expandVars(
"$a1 $b and c $d e f ",
{["a1 "]="(match is 'a1 ')", ["b and c "]="(match is 'b and c ')", ["d e f "]="(match is 'd e f ')", }
)
This prints
(match is 'a1 ')(match is 'b and c ')(match is 'd e f ')
Solution:
The variable names must match keys from your table; you could accepts keys that have spaces and all sort of characters but then you are forcing the user to use [] in the table keys, as done above, this is not very nice :)
Better keep it to alphanumeric and underscore, with the constraint that it cannot start with a number. This means to be generic you want a letter (%a), followed by any number of (including none) (* rather than +) of alphanumeric and underscore [%w_]:
function expandVars(tmpl,t)
return string.gsub(tmpl, '%$(%a[%w_]*)', t)
end
local sentence = expandVars(
"$a $b1 and c $d_2 e f ",
{a="(match is 'a')", b1="(match is 'b1')", d_2="(match is 'd_2')", }
)
print(sentence)
This prints
(match is 'a') (match is 'b1') and c (match is 'd_2') e f; non-matchable: $_a $1a b
which shows how the leading underscore and leading digit were not accepted.
exchangeSymbols "a§ b$ c. 1. 2. 3/" = filter (Char.isAlphaNum) (replaceStr str " " "_")
The code above is supposed to first replace all "spaces" with "_", then filter the String according to Char.isAlphaNum. Unfortunately the Char.isAlphaNum part absorbs the already exchanged "_", which isn't my intention and i want to hold the "_". So, i thought it would be nice just add an exception to the filter which goes like:
exchangeSymbols "a§ b$ c. 1. 2. 3/" = filter (Char.isAlphaNum && /='_') (replaceStr str " " "_")
You see the added && not /='_'. It produces a parse error, obviously it is not so easily possible to concatenate filter options, but is there a smart workaround ? I thought about wrapping the filter function, like a 1000 times or so with each recursion adding a new filter test (/='!'),(/='§') and so on without adding the (/='_'). However it doesn't seem to be a handy solution.
Writing
... filter (Char.isAlphaNum && /='_') ...
is actually a type error (the reason why it yields a parse error is maybe that you used /= as prefix - but its an infix operator). You cannot combine functions with (&&) since its an operator on booleans (not on functions).
Acutally this code snipped should read:
... filter (\c -> Char.isAlphaNum c && c /= '_') ...
Replace your filter with a list comprehension.
[x | x <- replaceStr str " " "_", x /= '_', Char.isAplhaNum x]
Naturally, you probably want to have multiple exceptions. So define a helper function:
notIn :: (Eq a) => [a] -> a -> Bool
notIn [] _ = True
notIn x:xs y = if x == y
then False
else notIn xs
EDIT: Apparently you can use notElem :: (Eq a) => a -> [a] -> Bool instead. Leaving above code for educational purposes.
And use that in your list comprehension:
[x | x <- replaceStr str " " "_", notElem x "chars to reject", Char.isAlphaNum x]
Untested, as haskell isn't installed on this machine. Bonus points if you are doing a map after the filter, since you can then put that in the list comprehension.
Edit 2: Try this instead, I followed in your footsteps instead of thinking it out myself:
[x | x <- replaceStr str " " "_", Char.isAlphaNum x || x == ' ']
[x | x <- replaceStr str " " "_", Char.isAlphaNum x || x `elem` "chars to accept"]
At this point the list comprehension doesn't help much. The only reason I did change it was because I you requested an &&, for which using a list comprehension is great.
Since it seems that you don't quite understand the principle of the list comprehension, its basically applying a bunch of filters and then a map with more than one source, for example:
[(x, y, x + y) | x <- [1, 2, 3, 4, 5], y <- [2, 4], x > y]