I have a meteor app for which I added the search-source package to search certain collections and it works partially. That is, when I search for the term foo bar it returns results for each of "foo" and "bar". This is fine, but I want to also be able to wrap the terms in quotes this way: "foo bar" and get results for an exact match only. at the moment when i do this i get an empty set. Here is my server code:
//Server.js
SearchSource.defineSource('FruitBasket', function(searchText, options) {
// options = options || {}; // to be sure that options is at least an empty object
if(searchText) {
var regExp = buildRegExp(searchText);
var selector = {$or: [
{'fruit.name': regExp},
{'fruit.season': regExp},
{'fruit.treeType': regExp}
]};
return Basket.find(selector, options).fetch();
} else {
return Basket.find({}, options).fetch();
}
});
function buildRegExp(searchText) {
// this is a dumb implementation
var parts = searchText.trim().split(/[ \-\:]+/);
return new RegExp("(" + parts.join('|') + ")", "ig");
}
and my client code:
//Client.js
Template.dispResults.helpers({
getPackages_fruit: function() {
return PackageSearch_fruit.getData({
transform: function(matchText, regExp) {
return matchText.replace(regExp, "<b>$&</b>")
},
sort: {isoScore: -1}
});
}
});
Thanks in advance!
I've modified the .split pattern so that it ignores everything between double quotes.
/[ \-\:]+(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/
Thus, you can simply wrap an exact phrase search in double quotes and it won't get split.
There is one more thing; since we don't need the quotes, they are removed in the next line using a .map function with a regex that replaces double quotes at the start or the end of a string part: /^"|"$/
Sample code:
function buildRegExp(searchText) {
// exact phrase search in double quotes won't get split
var arr = searchText.trim().split(/[ \-\:]+(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/);
var parts = arr.map(function(x){return x.replace(/^"|"$/g, '');});
return new RegExp("(" + parts.join('|') + ")", "ig");
}
console.log(buildRegExp("foo bar"));
console.log(buildRegExp("\"foo bar\""));
I'm working on some Groovy code to take text that's meant to be a Tweet, and turn all hashtags into web-links to the Twitter hashtag. In fact, I have that code working, but it fails when there's a bare # in the text that's meant to be read as a "number sign" instead of a hashtag.
The working (except for that edge case) code is:
static replaceHashTags(input) {
while (input.contains(/#/)) {
input = input.replaceAll(/(.*)#(\w+)(.*)/, { all, before, hashtag, after ->
"${before}<a href='https://twitter.com/hashtag/${hashtag}'>${hashtag}</a>${after}"
})
}
input.replaceAll(/<a href='https:\/\/twitter.com\/hashtag/, '#<a href=\'https://twitter.com/hashtag')
}
Instead of breaking what is mostly-working code before I had a solution, I wrote a test class to try out my new matching code. It's failing, and I can't figure out why. Here's the test class:
class StringTest {
def checkContains(string, expression) {
string.contains(expression)
}
#Test
void shouldTestSomethingElse() {
assert (checkContains('This is a string', /is/)) // Passes
assert !(checkContains('This is a string', /werigjweior/)) // Passes
assert (checkContains('#This tweet starts with a hashtag', /#This/)) // Passes
assert (checkContains('#This tweet starts with a hashtag', /#(\w+)/)) // Fails.
}
}
As I said, I'm not sure why that last assert fails. What my expectation was going into this exercise was that I could simply replace while (input.contains(/#/)) { with while (input.contains(/#(\w+)/)) {...But that doesn't seem to be the case.
I'm not convinced string.contains() accepts regex as argument. This works for me:
def checkContains(string, expression) {
string =~ expression
}
assert (checkContains('This is a string', /is/))
assert !(checkContains('This is a string', /werigjweior/))
assert (checkContains('#This tweet starts with a hashtag', /#This/))
assert (checkContains('#This tweet starts with a hashtag', /#(\w+)/))
Use ==~ to match the whole string.
I have a huge file with a lot of stuff that looks like:
skaune.malmo = rsr.path("m 640.4,516.9 3.9,-2.8 23.8,1.2 13.6,-5.2 3,-3.9 17.4,-1.8 1.2,-3.4 9.7,-4.6 0.5,-1.5 -7.3,-10.3 12.5,-4.5 -2.3,-4.1 3.9,-6.1 -3.4,-11.3 -2.7,-4.6 -2.3,-1.1 -6.4,3.4 -7.2,-0.7 -1.2,-6.8 -5.6,1.1 0,-10.6 -6.8,-5.7 0,-1.1 -11.4,-4.1 -4.1,4.1 0,2.3 1.9,1.5 0,3 -1.9,1.1 -1.1,1.6 -7.2,3 -5.3,0.4 -2.7,1.1 -5.2,5.7 -3.4,3.4 -10.2,5.2 -2.7,3.4 -3,4.6 -1.1,4.5 0,6.8 0,5.7 0.7,5 5.6,12.4 3.4,9.8 3.4,3.9").attr({id: 'path4',parent: 'Skanska_kommuner',fill: '#5eacdd','stroke-width': '0','stroke-opacity': '1'}).transform("t-40.677966,-76.271186").data('id', 'path4');
skaune.bjuv = rsr.path("m 643.8,137 -6.3,-2.8 -2.3,6.8 0,2.8 4.1,10.8 5,8 4.1,0 -0.7,7.3 -3.9,4 3.9,1.2 5.2,12.4 0,1.2 -1.1,2.7 -10.9,-1.1 -1.6,1.8 2.7,3.4 3,-1.2 1.1,5.7 -1.1,5.7 2.7,2.2 -2.7,-0.6 0,0.6 -0.7,5.7 3.4,1.2 1.1,-3 9.8,7.5 2.3,-3.4 3.8,2.3 7.5,-3 7.9,-4.5 -3.4,-11.8 10.2,5 1.6,-2.8 -6.8,-6.3 4.1,-11.3 -4.5,-5 5,-4.6 5.2,0.5 3.8,-8.4 1.8,-5.2 6.9,0 -2.3,-11.4 -3.4,0.7 -4.6,-3.4 -12.4,-14.7 -5.2,2.2 -14.8,-8.6 -3.8,0.7 -5.3,0 -1.5,0 1.5,3.9 -3.4,0 -5,6.8").attr({id: 'path6',parent: 'Skanska_kommuner',fill: '#5eacdd','stroke-width': '0','stroke-opacity': '1'}).transform("t-40.677966,-76.271186").data('id', 'path6');
skaune.astarp = rsr.path("m 713,149.4 3.9,-5.6 -8,-5 8,-13.2 -8,-8.4 -5.6,-18.1 -10.7,2.3 0,-6.8 -7.5,-9.1 -7.2,3.8 -9.8,0 0,3 -6.8,16.3 -3.8,4.5 -13.7,2.3 0,-3.4 -5.6,0.7 0,3.9 -14.8,3.3 1.2,5.7 -1.2,1.8 -1.8,2.8 1.8,4 1.2,2.8 2.7,1.8 7.9,3.4 1.8,-8 6.8,2.8 5,-6.8 3.4,0 -1.5,-3.9 1.5,0 5.3,0 3.8,-0.7 14.8,8.6 5.2,-2.2 12.4,14.7 8.4,6.8 0,-4.1 10.9,0").attr({id: 'path8',parent: 'Skanska_kommuner',fill: '#5eacdd','stroke-width': '0','stroke-opacity': '1'}).transform("t-40.677966,-76.271186").data('id', 'path8');
skaune.orkelljunga = rsr.path("m 753.8,1.6 10.7,-5.7 9.8,-9.1 0,-6.3 18.1,-16.4 15.9,-2.2 13.6,-15.5 19.3,-1.5 7.9,-6.4 12.5,14.8 4.5,-3.4 10.2,5.2 13.6,-3 6.8,-3.8 0.5,2.2 -7.3,1.6 -0.7,9.8 -20.4,10.6 -5,16.6 -4.5,1.6 6.1,25.6 -6.8,2.3 1.8,5.6 -4,2.3 -3.9,-9.1 -7.9,-1.1 -4.6,7.9 -4.5,0.5 0,9.1 -4.5,6.8 -25.7,-2.7 -27.6,32.8 -14.3,-2.2 -3.9,3.8 0,6.4 -6.8,6.1 -8.6,-3.9 1.8,-8.6 -7.9,0.7 -3.4,-7.9 -9.1,-5.7 -2.3,-7.9 11.4,-4.6 -10.9,-5.2 2.9,-3.8 1.2,0 6.8,-1.2 9,-9.1 10.2,-17.6 0,-8.4").attr({id: 'path10',parent: 'Skanska_kommuner',fill: '#5eacdd','stroke-width': '0','stroke-opacity': '1'}).transform("t-40.677966,-76.271186").data('id', 'path10');
and so on... It has a function called .attr({/alot of different stuff i want to delete/}) and I want to replace that with a variable called attr.(style). So everything inside { ... } should be replaced with style. How do I do that? What is the regexp string for { and everything inside }?
Any help appreciated.
You haven't said what kind of regex, but in most types I know you're looking for:
attr\({[^}]+}\)
...and replacing with attr(style) (or attr.(style), if that . after attr wasn't a typo). Depending on regex flavor, you may have to add or remove some backslashes there (for instance, with vim's default magic settings, I believe it would be attr({[^}]\+})). Basically:
Match attr({ literally
Match all characters within the {} using [^}]+
Match }) literally