Guess Look behind caused a blank page on iOS device [duplicate] - ios

I am looking for an alternative for this:
(?<=\.\d\d)\d
(Match third digit after a period.)
I'm aware I can solve it by using other methods, but I have to use a regular expression and more importantly I have to use replace on the string, without adding a callback.

Turn the lookbehind in a consuming pattern and use a capturing group:
And use it as shown below:
var s = "some string.005";
var rx = /\.\d\d(\d)/;
var m = s.match(/\.\d\d(\d)/);
if (m) {
console.log(m[1]);
}
Or, to get all matches:
const s = "some string.005 some string.006";
const rx = /\.\d\d(\d)/g;
let result = [], m;
while (m = rx.exec(s)) {
result.push(m[1]);
}
console.log( result );
An example with matchAll:
const result = Array.from(s.matchAll(rx), x=>x[1]);
EDIT:
To remove the 3 from the str.123 using your current specifications, use the same capturing approach: capture what you need and restore the captured text in the result using the $n backreference(s) in the replacement pattern, and just match what you need to remove.
var s = "str.123";
var rx = /(\.\d\d)\d/;
var res = s.replace(rx, "$1");
console.log(res);

Related

Import JSON API into Google Sheets

I need to import some information from a JSON API URL into Google Sheets.
This is one example:
https://api-apollo.pegaxy.io/v1/game-api/race/details/69357391
I've been successful in importing basic information using IMPORTJSON available on Github:
https://github.com/bradjasper/ImportJSON/
But now I am faced with a type of information (is it an object? an array?) which seems to be different from the usual and I find myself unable to import this.
Here is a piece of it:
{
"id": 969228010,
"raceId": 69357391,
"pegaId": 20042,
"gate": 8,
"pegaAttributes": "{\"id\":20042,\"name\":\"Bajaj\",\"ownerId\":623299,\"raceClass\":1,\"races\":1369,\"win\":504,\"lose\":865,\"energy\":18,\"gender\":\"Male\",\"bloodLine\":\"Campona\",\"breedType\":\"Legendary\",\"speed\":4.95,\"strength\":0.33,\"wind\":3.36,\"water\":1.84,\"fire\":8.83,\"lighting\":6.93,\"position\":4000,\"finished\":true,\"raceTime\":35.855,\"result\":8,\"gate\":8,\"lastSpeed\":22.721521955555556,\"stage\":4,\"isTopSpeedReached\":false,\"bonusStage\":false,\"topSpeed\":22.721521955555556,\"s0\":0,\"j0\":-0.02,\"a0\":0.4982185622222222,\"v0\":20.127527583333332,\"t0\":179.60000000000002,\"gears\":{},\"pb\":0}"**,
"position": 11,
"raceTime": 35.855,
"reward": 0
},
So using IMPORTJSON if I wanted to simply import the "raceId" element I'd go about doing this:
=ImportJSON("https://api-apollo.pegaxy.io/v1/game-api/race/details/69357391", "/race/registers/raceId", "noHeaders")
But when trying to import any information from within pegaAttributesthe IMPORTJSON is unable to recognize it as separate. The best I can do is import the whole block like so:
=ImportJSON("https://api-apollo.pegaxy.io/v1/game-api/race/details/69357391", "/race/registers/pegaAttributes", "noHeaders")
So some of the information after "pegaAttributes" and inside brackets { } I need to import. For example the attributes raceTime , topSpeed, lastSpeed and so on, how can I import this into Google Sheets?
Could anyone provide any pointers on how to do this? Thank you.
Try (you will have to apply JSON.parse on the pegaAttributes element which is also a json)
=importDataJSON(url,"id|position|raceTime","name|raceTime|topSpeed|lastSpeed")
with
function importDataJSON(url, items1, items2) {
let result = []
result = [[items1.split('|'), items2.split('|')].flat()]
const obj = JSON.parse(UrlFetchApp.fetch(url).getContentText())
obj.race.registers.forEach(o => {
let prov = []
items1.split('|').forEach(item1 => prov.push(o[item1]))
var pegaAttributes = JSON.parse(o.pegaAttributes)
items2.split('|').forEach(item2 => prov.push(pegaAttributes[item2]))
result.push(prov)
})
return result
}
with as parameters:
url
items1 (level 1) separated by |
items2 (level2, under pegaAttributes) separated by |
new edit
=importDataJSON(url,"totalReward|length","id|position|raceTime","name|raceTime|topSpeed|lastSpeed")
with
function importDataJSON(url, items0, items1, items2) {
let result = []
result = [[items0.split('|'), items1.split('|'), items2.split('|')].flat()]
const obj = JSON.parse(UrlFetchApp.fetch(url).getContentText())
let prov = []
items0.split('|').forEach(item0 => prov.push(obj.race[item0]))
result.push(prov)
obj.race.registers.forEach(o => {
let prov = []
items0.split('|').forEach(item0 => prov.push(''))
items1.split('|').forEach(item1 => prov.push(o[item1]))
var pegaAttributes = JSON.parse(o.pegaAttributes)
items2.split('|').forEach(item2 => prov.push(pegaAttributes[item2]))
result.push(prov)
})
return result
}
You have to parse it twice as that's an object just as text. I think using the custom formula might not be easiest since Google App Scripts can do this for you pretty cleanly. Consider using the standard JSON.parse() functions.
The below function got me the following values you were looking for. See the debug screen shot.
function getJSONData(){
const zURL = 'https://api-apollo.pegaxy.io/v1/game-api/race/details/69357391';
var response = UrlFetchApp.fetch(zURL);
var cleanedResponse = JSON.parse(response);
var theRace = cleanedResponse['race'];
var theRegisters = theRace['registers'];
var aRegister = theRegisters[0];
var oneID = oneRegister.id;
var aGate = oneRegister.gate;
var aPega = oneRegister.pegaAttributes;
var cleanedPega = JSON.parse(aPega);
var zTopSpeed = cleanedPega.topSpeed;
}
If you debug this, function and check to the right in your variables, you should be able to get everything you need. You'll have to find a way to get it back into sheets, but the values are available.
Updated
A request was made to figure out how this could be run as a Sheets Function. leveraging Mike Steelson's approach and presumption for what is needed as far as races... here's a function that could be used. Just paste the URL in the formula.
function getDataMyJSON(theURL) {
const data = JSON.parse(UrlFetchApp.fetch(theURL).getContentText())
const items = ['raceTime','topSpeed','lastSpeed']
let result=[]
data.race.registers.forEach(x => {
let prov = []
prov.push(x.raceId)
var p = JSON.parse(x.pegaAttributes)
items.forEach(i => prov.push(p[i]))
result.push(prov)
})
return result;
}
So then put the URL in the formula and you'd get this...

box callback functions returning the same string in Rascal

I'm trying to draw some boxes in Rascal and trying to give each box its own callback function. On entering the box with the mouse the corresponding string should get displayed in the text element (so hovering box1 should display box1 etc.).
However, at the moment the text does pop up but just displays "box3" for each of the 3 boxes.
Any ideas?
strings = ["box1", "box2", "box3"];
boxes = [ box(
size(100, 100),
onMouseEnter(void() {
output = s;
})
) | s <- strings];
render(hcat([
vcat(boxes),
text(str () {return output;})
]));
Good question, classical problem. The essence of the problem is that Rascal uses "non-capturing closures": this means that functions that are returned from another function share the same context. In your case this is the variable s introduced by s <- strings. This nearly always happens when you create function values in a loop (as you do here). The solution is to wrap another function layer around the returned function.
Here is a simple example:
list[int()] makeClosures()
= [ int() {return i;} | i <- [0,1,2]];
void wrong(){
lst = makeClosures();
println(lst[0]());
println(lst[1]());
println(lst[2]());
}
which will print surprisingly the values 2,2and2`. The solution is, as said, to introduce another function level:
int() makeClosure(int i)
= int() { return i;};
list[int()] makeClosuresOK()
= [ makeClosure(i) | i <- [0,1,2]];
void right(){
lst = makeClosuresOK();
println(lst[0]());
println(lst[1]());
println(lst[2]());
}
now calling right() will print 1, 2, and 3 as expected.
I leave it as an exercise how this is done in your example, but I am prepared to give a solution when you ask for it. Good luck!

How can one to dynamically parse a CSV file using C# and the Smart Format Detector in FileHelpers 3.1?

As per in this FileHelpers 3.1 example, you can automatically detect a CSV file format using the FileHelpers.Detection.SmartFormatDetector class.
But the example goes no further. How do you use this information to dynamically parse a CSV file? It must have something to do with the DelimitedFileEngine but I cannot see how.
Update:
I figured out a possible way but had to resort to using reflection (which does not feel right). Is there another/better way? Maybe using System.Dynamic? Anyway, here is the code I have so far, it ain't pretty but it works:
// follows on from smart detector example
FileHelpers.Detection.RecordFormatInfo lDetectedFormat = formats[0];
Type lDetectedClass = lDetectedFormat.ClassBuilderAsDelimited.CreateRecordClass();
List<FieldInfo> lFieldInfoList = new List<FieldInfo>(lDetectedFormat.ClassBuilderAsDelimited.FieldCount);
foreach (FileHelpers.Dynamic.DelimitedFieldBuilder lField in lDetectedFormat.ClassBuilderAsDelimited.Fields)
lFieldInfoList.Add(lDetectedClass.GetField(lField.FieldName));
FileHelperAsyncEngine lFileEngine = new FileHelperAsyncEngine(lDetectedClass);
int lRecNo = 0;
lFileEngine.BeginReadFile(cReadingsFile);
try
{
while (true)
{
object lRec = lFileEngine.ReadNext();
if (lRec == null)
break;
Trace.WriteLine("Record " + lRecNo);
lFieldInfoList.ForEach(f => Trace.WriteLine(" " + f.Name + " = " + f.GetValue(lRec)));
lRecNo++;
}
}
finally
{
lFileEngine.Close();
}
As I use the SmartFormatDetector to determine the exact format of the incoming Delimited files you can use following appoach:
private DelimitedClassBuilder GetFormat(string file)
{
var detector = new FileHelpers.Detection.SmartFormatDetector();
var format = detector.DetectFileFormat(file);
return format.First().ClassBuilderAsDelimited;
}
private List<T> ConvertFile2Objects<T>(string file, out DelimitedFileEngine engine)
{
var format = GetSeperator(file); // Get Here your FormatInfo
engine = new DelimitedFileEngine(typeof(T)); //define your DelimitdFileEngine
//set some Properties of the engine with what you need
engine.ErrorMode = ErrorMode.SaveAndContinue; //optional
engine.Options.Delimiter = format.Delimiter;
engine.Options.IgnoreFirstLines = format.IgnoreFirstLines;
engine.Options.IgnoreLastLines = format.IgnoreLastLines;
//process
var ret = engine.ReadFileAsList(file);
this.errorCount = engine.ErrorManager.ErrorCount;
var err = engine.ErrorManager.Errors;
engine.ErrorManager.SaveErrors("errors.out");
//return records do here what you need
return ret.Cast<T>().ToList();
}
This is an approach I use in a project, where I only know that I have to process Delimited files of multiple types.
Attention:
I noticed that with the files I recieved the SmartFormatDetector has a problem with tab delimiter. Maybe this should be considered.
Disclaimer: This code is not perfected but in a usable state. Modification and/or refactoring is adviced.

Doc Shell Swapping Example

I'm trying to write a simple example to show docshell swapping from one iframe to another.
I wrote this, can run from scratchpad with environment browser:
var doc = gBrowser.contentDocument;
var iframeA = doc.createElement('iframe');
iframeA.setAttribute('id', 'a');
iframeA.setAttribute('src', 'http://www.bing.com');
doc.documentElement.appendChild(iframeA);
var iframeB = doc.createElement('iframe');
iframeB.setAttribute('id', 'b');
iframeB.setAttribute('src', 'data:text/html,swap to here');
doc.documentElement.appendChild(iframeB);
doc.defaultView.setTimeout(function() {
var srcFrame = iframeA;
var targetFrame = iframeB;
doc.defaultView.alert('will swap now');
srcFrame.QueryInterface(Ci.nsIFrameLoaderOwner).swapFrameLoaders(targetFrame)
doc.defaultView.alert('swap done');
}, 5000)
However this throws this error when it tries to swap:
/*
TypeError: Argument 1 of HTMLIFrameElement.swapFrameLoaders does not implement interface XULElement. Scratchpad/1:17
*/
Any ideas on how to fix?
Thanks
Thanks to #mook and #mossop from irc #extdev for the help.
The reason it didnt work was because:
pretty sure it needs to be a
Looks like gBrowser.contentDocument might be a html page? You must be using XUL elements
No idea if it even works in content either - I think it doesn't
and the things to be swapped must either both be type=content or neither can be, or something like that (translation: the type attribute of both source and target must be the same. so if one is content-primary the other must be content-primary as well)
This works:
var doc = document; //gBrowser.contentDocument;
var iframeA = doc.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'browser');
iframeA.setAttribute('id', 'a');
iframeA.setAttribute('src', 'http://www.bing.com');
iframeA.setAttribute('style', 'height:100px;');
doc.documentElement.appendChild(iframeA);
var iframeB = doc.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'browser');
iframeB.setAttribute('id', 'b');
iframeB.setAttribute('src', 'data:text/html,swap to here');
iframeB.setAttribute('style', 'height:100px;');
doc.documentElement.appendChild(iframeB);
doc.defaultView.setTimeout(function() {
var srcFrame = iframeA;
var targetFrame = iframeB;
doc.defaultView.alert('will swap now');
srcFrame.QueryInterface(Ci.nsIFrameLoaderOwner).swapFrameLoaders(targetFrame)
doc.defaultView.alert('swap done');
}, 5000)
so in other words even if you made iframe with xul namespace it would not swap if you put it in an html document. like this example here:
var xulDoc = document;
var doc = gBrowser.contentDocument;
var iframeA = xulDoc.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'iframe');
iframeA.setAttribute('id', 'a');
iframeA.setAttribute('src', 'http://www.bing.com');
iframeA.setAttribute('type', 'content');
iframeA.setAttribute('style', 'height:100px;width:100px;');
doc.documentElement.appendChild(iframeA);
var iframeB = xulDoc.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'iframe');
iframeB.setAttribute('id', 'b');
iframeB.setAttribute('src', 'data:text/html,swap to here');
iframeB.setAttribute('type', 'content');
iframeB.setAttribute('style', 'height:100px;width:100px;');
doc.documentElement.appendChild(iframeB);
doc.defaultView.setTimeout(function() {
var srcFrame = iframeA;
var targetFrame = iframeB;
doc.defaultView.alert('will swap now');
srcFrame.QueryInterface(Ci.nsIFrameLoaderOwner).swapFrameLoaders(targetFrame)
doc.defaultView.alert('swap done');
}, 5000)
It throws:
NS_ERROR_NOT_IMPLEMENTED: Scratchpad/2:21
this line is the swapFrameLoaders line
so its recommended to not use iframe with xul namespace as if you do you wont get the DOMContentLoaded and some other events http://forums.mozillazine.org/viewtopic.php?f=19&t=2809781&hilit=iframe+html+namespace
so its recommended to use element

What grammar is this?

I have to parse a document containing groups of variable-value-pairs which is serialized to a string e.g. like this:
4^26^VAR1^6^VALUE1^VAR2^4^VAL2^^1^14^VAR1^6^VALUE1^^
Here are the different elements:
Group IDs:
4^26^VAR1^6^VALUE1^VAR2^4^VAL2^^1^14^VAR1^6^VALUE1^^
Length of string representation of each group:
4^26^VAR1^6^VALUE1^VAR2^4^VAL2^^1^14^VAR1^6^VALUE1^^
One of the groups:
4^26^VAR1^6^VALUE1^VAR2^4^VAL2^^1^14 ^VAR1^6^VALUE1^^
Variables:
4^26^VAR1^6^VALUE1^VAR2^4^VAL2^^1^14^VAR1^6^VALUE1^^
Length of string representation of the values:
4^26^VAR1^6^VALUE1^VAR2^4^VAL2^^1^14^VAR1^6^VALUE1^^
The values themselves:
4^26^VAR1^6^VALUE1^VAR2^4^VAL2^^1^14^VAR1^6^VALUE1^^
Variables consist only of alphanumeric characters.
No assumption is made about the values, i.e. they may contain any character, including ^.
Is there a name for this kind of grammar? Is there a parsing library that can handle this mess?
So far I am using my own parser, but due to the fact that I need to detect and handle corrupt serializations the code looks rather messy, thus my question for a parser library that could lift the burden.
The simplest way to approach it is to note that there are two nested levels that work the same way. The pattern is extremely simple:
id^length^content^
At the outer level, this produces a set of groups. Within each group, the content follows exactly the same pattern, only here the id is the variable name, and the content is the variable value.
So you only need to write that logic once and you can use it to parse both levels. Just write a function that breaks a string up into a list of id/content pairs. Call it once to get the groups, and then loop through them calling it again for each content to get the variables in that group.
Breaking it down into these steps, first we need a way to get "tokens" from the string. This function returns an object with three methods, to find out if we're at "end of file", and to grab the next delimited or counted substring:
var tokens = function(str) {
var pos = 0;
return {
eof: function() {
return pos == str.length;
},
delimited: function(d) {
var end = str.indexOf(d, pos);
if (end == -1) {
throw new Error('Expected delimiter');
}
var result = str.substr(pos, end - pos);
pos = end + d.length;
return result;
},
counted: function(c) {
var result = str.substr(pos, c);
pos += c;
return result;
}
};
};
Now we can conveniently write the reusable parse function:
var parse = function(str) {
var parts = {};
var t = tokens(str);
while (!t.eof()) {
var id = t.delimited('^');
var len = t.delimited('^');
var content = t.counted(parseInt(len, 10));
var end = t.counted(1);
if (end !== '^') {
throw new Error('Expected ^ after counted string, instead found: ' + end);
}
parts[id] = content;
}
return parts;
};
It builds an object where the keys are the IDs (or variable names). I'm asuming as they have names that the order isn't significant.
Then we can use that at both levels to create the function to do the whole job:
var parseGroups = function(str) {
var groups = parse(str);
Object.keys(groups).forEach(function(id) {
groups[id] = parse(groups[id]);
});
return groups;
}
For your example, it produces this object:
{
'1': {
VAR1: 'VALUE1'
},
'4': {
VAR1: 'VALUE1',
VAR2: 'VAL2'
}
}
I don't think it's a trivial task to create a grammar for this. But on the other hand, a simple straight forward approach is not that hard. You know the corresponding string length for every critical string. So you just chop your string according to those lengths apart..
where do you see problems?

Resources