Replace expression with subsection using regex? - regex

My IDE PHPstorm allows you to do search and replace using regex, one of the things I find myself often doing is switching the order or action, aka, in function a I will set a value on items from list a using list b as the values.
but then in function b I want to invert it.
so I want to set a value on items from list b using list a as the values.
A proper example is this:
var $clipDetailsGame = $('#clipDetailsGame');
var $clipDetailsTitle = $('#clipDetailsTitle');
var $clipDetailsByline = $('#clipDetailsByline');
var $clipDetailsTeamOne = $('#clipDetailsTeamOne');
var $clipDetailsTeamTwo = $('#clipDetailsTeamTwo');
var $clipDetailsReferee = $('#clipDetailsReferee');
var $clipDetailsDescription = $('#clipDetailsDescription');
var $clipDetailsCompetition = $('#clipDetailsCompetition');
function a(clip){
clip.data('gameId' , $clipDetailsGame.val());
clip.data('title' , $clipDetailsTitle.val());
clip.data('byline' , $clipDetailsByline.val());
clip.data('team1' , $clipDetailsTeamOne.val());
clip.data('team2' , $clipDetailsTeamTwo.val());
clip.data('refereeId' , $clipDetailsReferee.val());
clip.data('description' , $clipDetailsDescription.val());
clip.data('competitionId', $clipDetailsCompetition.val());
}
function b (clip){
$clipDetailsGame .val(clip.data('gameId'));
$clipDetailsTitle .val(clip.data('title'));
$clipDetailsByline .val(clip.data('byline'));
$clipDetailsTeamOne .val(clip.data('team1'));
$clipDetailsTeamTwo .val(clip.data('team2'));
$clipDetailsReferee .val(clip.data('refereeId'));
$clipDetailsDescription.val(clip.data('description'));
$clipDetailsCompetition.val(clip.data('competitionId'));
}
Excluding the formatting (It's just there to make my point clearer), what kind of regex could I use to do the replacement for me?

Basic regex -- nothing fancy or complex at all
Search for: (clip\.data\('[a-zA-Z0-9]+')\s*, (\$[a-zA-Z0-9]+\.val\()(\)\);)
Replace with: \$2\$1\$3
The only PhpStorm-related thing here is replacement string format -- you have to "escape" $ to have it work (i.e. it has to be \$2 to use 2nd back-trace instead of just $2 or \2 (as used in other engines)).
This will transform this:
clip.data('gameId' , $clipDetailsGame.val());
clip.data('title' , $clipDetailsTitle.val());
clip.data('byline' , $clipDetailsByline.val());
clip.data('team1' , $clipDetailsTeamOne.val());
clip.data('team2' , $clipDetailsTeamTwo.val());
clip.data('refereeId' , $clipDetailsReferee.val());
clip.data('description' , $clipDetailsDescription.val());
clip.data('competitionId', $clipDetailsCompetition.val());
into this:
$clipDetailsGame.val(clip.data('gameId'));
$clipDetailsTitle.val(clip.data('title'));
$clipDetailsByline.val(clip.data('byline'));
$clipDetailsTeamOne.val(clip.data('team1'));
$clipDetailsTeamTwo.val(clip.data('team2'));
$clipDetailsReferee.val(clip.data('refereeId'));
$clipDetailsDescription.val(clip.data('description'));
$clipDetailsCompetition.val(clip.data('competitionId'));
Useful link: http://www.jetbrains.com/phpstorm/webhelp/regular-expression-syntax-reference.html

Mopping up (not quite the answer to this question, but another way of organizing the code to make search and replace unnecessary):
var $details = {};
var fields = [
'Game', 'Title', 'Byline', 'TeamOne', 'TeamTwo', 'Referee', 'Description',
'Competition'
];
for(field in fields) {
$details[field] = $('#clipDetails' + field);
}
function a(clip) {
for(field in fields) {
clip.data(field, $details[fields].val());
}
}
function b(clip) {
for(field in fields) {
$details[field].val(clip.data(field));
}
}
Yes, I know that there are tiny naming inconsistencies that means that this isn't working out of the box, such as Game versus gameId. This is an excellent occasion to clean that up too :). If you still want to keep the title case for the ids (such as #clipDetailsGame in stead of #clipDetailsgame), keep it in title case in the fields array and use toLowerCase where you need lower case.
By the way, there is an interesting read on what makes DRY a good thing here: https://softwareengineering.stackexchange.com/questions/103233/why-is-dry-important

Related

Using split command to split a string

I am looking to split a string and put it into a set. The string to be split is an element of a tuple.
This string element in the tuple takes values such as(pitblockSet) :
{"P499,P376,P490,P366,P129,"}
{"P388,P491,P367,"}
{"P500,P377,P479,P355,"}
and so on. Each set refers to a Path Id(string name of the path)
The tuple was defined as :
tuple Path {
string id;
string source;
string dest;
{string} pitblockSet;
{string} roadPoints;
{string} dumpblockSet;
{string} others;
float dist;
};
And the above sets to be split refers to the element : {string} pitblockSet;
I now have to split the pitBlockSet. I am using the following :
{Path} Pbd={};
// Not putting the code to populate Pbd as it is irrelevant here
// there are several lines here for the purpose of creating set Pbd...
{string} splitPitBlocksPath[Pathid];
{string} splitDumpBlocksPath[Pathid];
execute {
for(var p in Pbd) {
var splitPitBlocksPath[p.id] = p.pitblockSet.split(",") ;
var splitDumpBlocksPath[p.id] = p.dumpblockSet.split(",") ;
}
}
The problem is when I execute it I get error in the above 2 lines appearing 4 times:
Scripting parser error: missing ';' or newline between statements.
I am not able to understand where I am going wrong
===============Added after Alex's Answer =============================
Thank you for the Answer again - It worked perfectly with some minor changes.
I might not have been able to explain the issue properly in the above hence adding the following. My actual code is much bigger and these are only an extract
Pbd for my case is a tuple of type {Path}. Path is described above. Pbd reads about 20,000 records from excel and each Pbd has tuple fields like id, source, dest, pitblockSet, dumpblockSet etc etc. These are all read from excel and populated into the tuple Pbd - this part is working fine. The 3 lines that I mentioned above were just for example of the Pbd.pitBlockSet for just 3 records out of the 20,000.
p.pitblockSet is a set but it contains only one string. The requirement is to break this string into a set. Like for example if p.pitblockSet has a value {"P499,P376,P490,P366,P129,"} for say p.id = "PT129" the expected result for this p.id is {"P499" "P376" "P490" "P366" "P129"}. Then say for example for p.id="PT1" the p.pitblockSet is {"P4,"} the expected result is a set with only one element like {"P4"}. As mentioned earlier there are several such records of p and the above two are just for example.
I have therefore modified the suggested code to some extent to fit into the problem. However I am still getting an issue with the split command.
{string} result[Pbd];
int MaxS=10;
execute {
for(var p in Pbd) {
var stringSet = Opl.item(p.pitblockSet,0);
var split= new Array(MaxS);
split=stringSet.split(",") ;
for(var i=0;i<=MaxS;i++) if ((split[i]!='null') && (split[i]!='')) result[p].add(split[i]);
writeln("result:", p.id, result[p]);
}
}
The Answers look like below :
result:PT1 {"P4"}
result:PT2 {"P5"}
result:PT3 {"P6"}
result:PT4 {"P7"}
result:PT5 {"P8"}
result:PT6 {"P8" "P330" "P455" "P341"}
result:PT7 {"P326"}
result:PT8 {"P327"}
result:PT9 {"P328"}
.
.
and so on
.
.
result:PT28097 {"P500" "P377" "P479" "P355"}
result:PT28098 {"P501" "P378" "P139"}
result:PT28099 {"P501" "P388" "P491" "P367"}
result:PT28100 {"P501" "P378" "P480"}
result:PT28101 {"P501" "P378" "P139"}
result:PT28102 {"P502"}
result:PT28103 {"P503"}
Unfortunately, I'm afraid you encounter a product limitation.
See: https://www.ibm.com/support/knowledgecenter/SSSA5P_12.10.0/ilog.odms.ide.help/refjsopl/html/intro.html?view=kc#1037020
Regards,
Chris.
int MaxS=10;
{string} splitDumpBlocksPath={"P499,P376,P490,P366,P129,"} union
{"P388,P491,P367,"} union
{"P500,P377,P479,P355,"};
range Pbd=0..card(splitDumpBlocksPath)-1;
{string} result[Pbd];
execute {
for(var p in Pbd) {
var stringSet=Opl.item(splitDumpBlocksPath,p);
writeln(stringSet);
var split= new Array(MaxS);
split=stringSet.split(",") ;
for(var i=0;i<=MaxS;i++) if ((split[i]!='null') && (split[i]!='')) result[p].add(split[i]);
}
writeln(result);
}
works fine and gives
P499,P376,P490,P366,P129,
P388,P491,P367,
P500,P377,P479,P355,
[{"P499" "P376" "P490" "P366" "P129"} {"P388" "P491" "P367"} {"P500" "P377"
"P479" "P355"}]

Matching parameters of a function with Regex

What I have so far: \w+\(((".+")|(\d+))+\)I'm not sure how to go about matching more than one paramter separated by a comma. How can I capture the parameters (and function names) of the following test cases?
scroll("foo")
scroll("foo",55)
scroll("foo","bar")
scroll("foo","bar",55)
scroll(55)
scroll(55,"foo")
scroll(55, 13,"foo","bar")
For example, in the last one the groups must be scroll, 55, 13, "foo", and "bar".
Edit: Language is AS3
Try this lengthy regex:
(\"?\w+\"?)\((\"?\w+\"?)(?:[,\s]+(\"?\w+\"?))?(?:[,\s]+(\"?\w+\"?))?(?:[,\s]+(\"?\w+\"?))?\)?
The code above is set to capture up to five parameters. You can adjust that by adding/removing this code (?:[,\s]+(\"?\w+\"?))? based on your needs.
Demo: https://regex101.com/r/o1RRSG/1
i hope i'm in right way
you want to split for example
this: scroll ( 55, 13, "foo", "bar" )
to its function name and arguments like
this: scroll ( 55, 13, "foo", "bar" )
a better result of expression:
i just assume additional white spaces for more accuracy
the regex fot would be :
[^\t (,)]
Okay, you may not like it, but it's flawless as long as you have ExternalInterface backed with JS available. And it's funny. (While doing this with reg exps is the opposite of fun.)
The idea is to let JS do its eval. The manual says you have to pass a function name to ExternalInterface.call(), which is not true: pass just any code that evaluates to a function reference. This way you can inject any JS code into the page where your SWF resides (which is why AllowScriptAccess is such a terribly dangerous attribute).
public class Test extends Sprite
{
public function Test()
{
var test = "scroll(55, 13,\"foo\",\"bar\", \"now(), we are \\\"screwed\\\")\")";
trace(test);
var details = parseFunctionCall(test);
trace(details[0]);
for (var i = 1; i<details.length; i++) {
trace("\t"+i+": "+typeof(details[i])+" "+details[i]);
}
}
private function parseFunctionCall(input:String):Array
{
if (ExternalInterface.available) {
var split:RegExp = /^(\w+)\((.+)\)$/;
var info = split.exec(input);
var inject = "(function(){return ["+info[2]+"];})";
var params = ExternalInterface.call(inject);
params.unshift(info[1]);
return params;
}
return null;
}
}
/*
Output:
scroll
1: number 55
2: number 13
3: string foo
4: string bar
5: string now(), we are "screwed")
*/

How do I query multiple IDs via the ContentSearchManager?

When I have an array of Sitecore IDs, for example TargetIDs from a MultilistField, how can I query the ContentSearchManager to return all the SearchResultItem objects?
I have tried the following which gives an "Only constant arguments is supported." error.
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(x => f.TargetIDs.Contains(x.ItemId));
rpt.DataBind();
}
I suppose I could build up the Linq query manually with multiple OR queries. Is there a way I can use Sitecore.ContentSearch.Utilities.LinqHelper to build the query for me?
Assuming I got this technique to work, is it worth using it for only, say, 10 items? I'm just starting my first Sitecore 7 project and I have it in mind that I want to use the index as much as possible.
Finally, does the Page Editor support editing fields somehow with a SearchResultItem as the source?
Update 1
I wrote this function which utilises the predicate builder as dunston suggests. I don't know yet if this is actually worth using (instead of Items).
public static List<T> GetSearchResultItemsByIDs<T>(ID[] ids, bool mustHaveUrl = true)
where T : Sitecore.ContentSearch.SearchTypes.SearchResultItem, new()
{
Assert.IsNotNull(ids, "ids");
if (!ids.Any())
{
return new List<T>();
}
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
var predicate = PredicateBuilder.True<T>();
predicate = ids.Aggregate(predicate, (current, id) => current.Or(p => p.ItemId == id));
var results = s.GetQueryable<T>().Where(predicate).ToDictionary(x => x.ItemId);
var query = from id in ids
let item = results.ContainsKey(id) ? results[id] : null
where item != null && (!mustHaveUrl || item.Url != null)
select item;
return query.ToList();
}
}
It forces the results to be in the same order as supplied in the IDs array, which in my case is important. (If anybody knows a better way of doing this, would love to know).
It also, by default, ensures that the Item has a URL.
My main code then becomes:
var f = (Sitecore.Data.Fields.MultilistField) rootItem.Fields["Main navigation links"];
rpt.DataSource = ContentSearchHelper.GetSearchResultItemsByIDs<SearchResultItem>(f.TargetIDs);
rpt.DataBind();
I'm still curious how the Page Editor copes with SearchResultItem or POCOs in general (my second question), am going to continue researching that now.
Thanks for reading,
Steve
You need to use the predicate builder to create multiple OR queries, or AND queries.
The code below should work.
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
var predicate = PredicateBuilder.True<SearchResultItem>();
foreach (var targetId in f.Targetids)
{
var tempTargetId = targetId;
predicate = predicate.Or(x => x.ItemId == tempTargetId)
}
rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(predicate);
rpt.DataBind();
}

Linq query not matching hrefs

I'm trying to write out all matches found using a regex with the code below:
var source = "<Content><link><a xlink:href=\"tcm:363-48948\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">Read more</a></link><links xlink:href=\"tcm:362-65596\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"/></Content>";
var tridionHref = new Regex("tcm:([^\"]*)");
var elem = XElement.Parse(source);
XNamespace xlink = "http://www.w3.org/1999/xlink";
if (tridionHref.IsMatch(elem.ToString()))
{
foreach (var Id in elem.Elements().Where(x => x.Attribute(xlink + "href") != null))
{
Console.WriteLine(Id.Attribute(xlink + "href").Value); //For testing
Id.Attribute(xlink + "href").Value = Id.Attribute(xlink + "href").Value.Replace("value1", "value2"); //Just to show you an example
}
}
My console window outputs tcm:362-65596 but not tcm:363-48948. It looks like the code doesn't see the value of xlink:href inside my <a> tag as an attribute? Can anyone point me in the right direction? I need to match ALL instances of tcm:([^\"]*).
The problem is you are not looking in the right place. Your elem.Elements is looking at the link element and the links element. Only one of these has the attribute that you are looking for. You'll need to select the elements you want to check more precisely before looking for the right attribute.
I've got it working. I didn't need a regex I just needed to get the Descendants instead inside my for loop. foreach (var Id in elem.Descendants().Where(x => x.Attribute(xlink + "href") != null))

AS3/Regular Expressions - Replacing segments of a string

I have absolutely no knowledge in Regex whatsoever. Basically what I'm trying to do is have an error class that I can use to call errors (obviously) which looks like this:
package avian.framework.errors
{
public class AvError extends Object
{
// errors
public static const LAYER_WARNING:String = "Warning: {0} is not a valid layer - the default layer _fallback_ has been used as the container for {1}.";
/**
* Constructor
* Places a warning or error into the output console to assist with misuse of the framework
* #param err The error to display
* #param params A list of Objects to use throughout the error message
*/
public function AvError(err:String, ...params)
{
trace(err);
}
}
}
What I want to be able to do is use the LAYER_WARNING like this:
new AvError(AvError.LAYER_WARNING, targetLayer, this);
And have the output be something along the lines of:
Warning: randomLayer is not a valid layer - the default layer _fallback_ has been used as the container for [object AvChild].
The idea is to replace {0} with the first parameter parsed in ...params, {1} with the second, etc.
I've done a bit of research and I think I've worked out that I need to search using this pattern:
var pattern:RegExp = /{\d}/;
You can use StringUtil
var original:String = "Here is my {0} and my {1}!";
var myStr:String = StringUtil.substitute(original, ['first', 'second']);
Using the g flag in RegExp you can create an array containing all of your {x} matches, then loop through this array and replace each of the matches with the appropriate parameter.
Code:
var mystring:String = "{0} went to {1} on {2}";
function replace(str:String, ...params):String
{
var pattern:RegExp = /{\d}/g;
var ar:Array = str.match(pattern);
var i:uint = 0;
for(i; i<ar.length; i++)
{
str = str.split(ar[i]).join(params[i]);
}
return str;
}
trace(replace(mystring, "marty", "work", "friday")); // marty went to work on friday
i'm assuming you want to have several static constants with varying replacement instances ({0}, {1}, {2}, etc.) in each string constant.
something like this should work - sorry, it's untested:
public function AvError(err:String, ...params)
{
var replacementArray:Array = err.match(new RegExp("{\\d}", "g"));
for (var i:int = 0, i < replacementArray.length, i++)
err = err.replace(new RegExp(replacementArray[i], "g"), params[i]);
trace(err);
}
if you do have several static constants with varying replacement instances, you'll want to check for an appropriate matching amount of …params that are passed.