I want to set a cursor in javascript so when I use regex, it recognizes what data it has already parsed, and continues from that point. Below is a snippet of code that shows what the file is like.
# vtk DataFile Version 4.0
-3659.0757 3746.6780 3628.1143
-3659.6714 3746.2517 3627.9539
-3660.1450 3745.8142 3627.9270
-3660.4631 3745.3735 3628.0605
-3660.6931 3745.0708 3628.1416
LINES 207 31529
581 0 1 2 3 4 ... 579 580
Currently I pick up the float float float pattern correctly, and I want my code to continue to LINES 207 31529 and then 581. This code picks up LINES, but instead of going to the 581 it goes back to the top of the file and takes 4 for numLines.
var LINES = /(LINES)[ ]+[\d]+[ ]+[\d]+[\n]/;
var recogLines = /[\d]+/;
var numLines = parseInt(recogLines.exec(data));
I saw something online about \G, but I don't think javascript recognizes that (or I'm just not using it correctly). How do I keep a cursor so the same data isn't iterated over and over again? Thanks!
I would suggest something along the lines of (may not be exactly syntactically correct):
var LINES = '/(LINES)[ ]+([\d]+)[ ]+([\d]+)\n/';
var data = <input>;
var output = new Array();
result = LINES.exec(data);
while(result) {
output.push([result[1], result[2], result[3]]);
result = LINES.exec(data.substring(result.index + result[0].length);
}
but at that point, I would use the global modifier:
var LINES = '/^(LINES)[ ]+([\d]+)[ ]+([\d]+)$/gm';
result = LINES.exec(data);
would give you an array:
array[0][2] // first LINE, first set of numbers
array[0][3] // first LINE, second set of numbers
array[1][2] // second LINE, first set of numbers
array[1][3] // second LINE, second set of numbers
Just my 2 cents.
Edit:
If you are writing a parse, I could see the reason for the first. Just add your code to parse the lines (and keep track of your cursor position) before running your pattern match again, and pass that to the substring instead of the index of the previous match plus the length of the match.
Related
This is an extension of this SO question
I made a function to see if i can correctly format any number. The answers below work on tools like https://regex101.com and https://regexr.com/, but not within my function(tried in node and browser):
const
const format = (num, regex) => String(num).replace(regex, '$1')
Basically given any whole number, it should not exceed 15 significant digits. Given any decimal, it should not exceed 2 decimal points.
so...
Now
format(0.12345678901234567890, /^\d{1,13}(\.\d{1,2}|\d{0,2})$/)
returns 0.123456789012345678 instead of 0.123456789012345
but
format(0.123456789012345,/^-?(\d*\.?\d{0,2}).*/)
returns number formatted to 2 deimal points as expected.
Let me try to explain what's going on.
For the given input 0.12345678901234567890 and the regex /^\d{1,13}(\.\d{1,2}|\d{0,2})$/, let's go step by step and see what's happening.
^\d{1,13} Does indeed match the start of the string 0
(\. Now you've opened a new group, and it does match .
\d{1,2} It does find the digits 1 and 2
|\d{0,2} So this part is skipped
) So this is the end of your capture group.
$ This indicates the end of the string, but it won't match, because you've still got 345678901234567890 remaining.
Javascript returns the whole string because the match failed in the end.
Let's try removing $ at the end, to become /^\d{1,13}(\.\d{1,2}|\d{0,2})/
You'd get back ".12345678901234567890". This generates a couple of questions.
Why did the preceding 0 get removed?
Because it was not part of your matching group, enclosed with ().
Why did we not get only two decimal places, i.e. .12?
Remember that you're doing a replace. Which means that by default, the original string will be kept in place, only the parts that match will get replaced. Since 345678901234567890 was not part of the match, it was left intact. The only part that matched was 0.12.
Answer to title question: your function doesn't replace, because there's nothing to replace - the regex doesn't match anything in the string. csb's answer explains that in all details.
But that's perhaps not the answer you really need.
Now, it seems like you have an XY problem. You ask why your call to .replace() doesn't work, but .replace() is definitely not a function you should use. Role of .replace() is replacing parts of string, while you actually want to create a different string. Moreover, in the comments you suggest that your formatting is not only for presenting data to user, but you also intend to use it in some further computation. You also mention cryptocurriencies.
Let's cope with these problems one-by-one.
What to do instead of replace?
Well, just produce the string you need instead of replacing something in the string you don't like. There are some edge cases. Instead of writing all-in-one regex, just handle them one-by-one.
The following code is definitely not best possible, but it's main aim is to be simple and show exactly what is going on.
function format(n) {
const max_significant_digits = 15;
const max_precision = 2;
let digits_before_decimal_point;
if (n < 0) {
// Don't count minus sign.
digits_before_decimal_point = n.toFixed(0).length - 1;
} else {
digits_before_decimal_point = n.toFixed(0).length;
}
if (digits_before_decimal_point > max_significant_digits) {
throw new Error('No good representation for this number');
}
const available_significant_digits_for_precision =
Math.max(0, max_significant_digits - digits_before_decimal_point);
const effective_max_precision =
Math.min(max_precision, available_significant_digits_for_precision);
const with_trailing_zeroes = n.toFixed(effective_max_precision);
// I want to keep the string and change just matching part,
// so here .replace() is a proper method to use.
const withouth_trailing_zeroes = with_trailing_zeroes.replace(/\.?0*$/, '');
return withouth_trailing_zeroes;
}
So, you got the number formatted the way you want. What now?
What can you use this string for?
Well, you can display it to the user. And that's mostly it. The value was rounded to (1) represent it in a different base and (2) fit in limited precision, so it's pretty much useless for any computation. And, BTW, why would you convert it to String in the first place, if what you want is a number?
Was the value you are trying to print ever useful in the first place?
Well, that's the most serious question here. Because, you know, floating point numbers are tricky. And they are absolutely abysmal for representing money. So, most likely the number you are trying to format is already a wrong number.
What to use instead?
Fixed-point arithmetic is the most obvious answer. Works most of the time. However, it's pretty tricky in JS, where number may slip into floating-point representation almost any time. So, it's better to use decimal arithmetic library. Optionally, switch to a language that has built-in bignums and decimals, like Python.
I am newbie using Javascript in Adobe. I have written script that catch the file name and add it as a title in the document, but problem is it doesn't split in 2 lines long file names. So long text file names are out of the page border.
For example file name is
"This is a text that I need to split in two lines How to write the script in order to split the long text and fit in the page"
This is just a sample. What I need to edit? And is it possible?
var trFileName = this.documentFileName.replace(/.*\/|\.pdf$/ig,""); //remove .pdf extension
var pageAmount = this.numPages; //define how many pages are there
this.addWatermarkFromText({
cText: trFileName,
nStart: 0,
nEnd: pageAmount,
nFontSize: 18,
aColor: color.blue,
cFont: "Helvetica-Bold",
nTextAlign: app.constants.align.center,
nHorizAlign: app.constants.align.center,
nVertAlign: app.constants.align.top,
//nHorizValue: -25,
nVertValue: -87.87
})
So looking at the documentation for Acrobat the quick way to do this is to add and use the bPercentage: -1 property which ought to scale the watermark to fit the page with a max of 100%. Obviously, the longer the text, the smaller the the typesize, but it ought to only scale when needed.
The big problem here is "how big is too big?" Since most fonts are not fixed-width. So if you do not have some function to check the size of the type in that font, you would need to set up a temp image, set the type, then measure the dimensions of the image, then decide how much to break the text.
The worst case for English though is probably going to be an endless string of W, so if you want to hard code the font size and some reasonable character limit, you can get a reasonable max character count by counting how many Ws it takes to go out of bounds.
Once you have that number you can split the string.
One way to split a string is to use substring:
var cDisplayText = trFilename;
var nMaxChars = 10;
var cAdobeNewline = '\r';
var cLineBreakChar = '-';
if (cDisplayText.length > nMaxChars && cDisplayText.length > 0) {
cDisplayText = cDisplayText.substring(0, nMaxChars)
+ cLineBreakChar
+ cAdobeNewline
+ cDisplayText.substring(nMaxChars);
}
And then replace cText: trFileName, with cText: cDisplayText,
I have not tested this and my javascript has atrophied a little, but the idea is to test the string length and insert a hyphen and a line break.
This (obviously) does not account for case where there is more than 1 line break required.
I have $45.00 as string and need to get 45 out of that.
following is working...
How do I write this in one line?
var x= "$45.00" ,cents =/\.00$/;
var z= x.replace(/^\$/,'');
z = z.replace(cents,'');
Basically, the .replace() calls can be daisy-chained, with the second one acting on the results of the first:
var x = "$45.00", cents = /\.00$/, z = x.replace(/^\$/, '').replace(cents, '');
If the question is that straight forward you can simply use this one line to get the left of the dot value.
var x= "$45.00".split('$')[1].split('.')[0];
Explanation:
You assign the variable x to the price string in this case
"$45.00"
Then use the string function split, to divide the string into two
arrays.
Right now you have ["$"] in position zero and the rest in position 1
["45.00"]
You then use the same function on the second array at position one
to divide at the dot character.
Now you have at position zero ["45"] and position 1 [".00"]
You need position 0 so that's the index you you will use and that's
it.
I think it's pretty straightforward but tried to be as through as possible.
I'm forming a URL which can't have leading zeroes in the dist GET parameter filled with distance[i].
trr2.innerHTML= "<b><a href='join.php?id="+idO[i]+"&dist="+distance[i] +"&category="+category[i]+"&min="+min[i]+"&max="+max[i]+"'>Join this deal</a>";
The link generated in this prints distance[i] with a leading 0 and then decimal point when the number is less than zero, for example "...&dist=0.6..." which in turn is causing errors with the postgresql call I generate with this expression. I tried all of the following to either remove the leading 0 from the number or cast the number explicitly to a number in hopes that this would suppress the leading zero:
var dis = distance[i]
...following by any of these....
var disNN = dis.replace("0", ""); //there will only be 0's in the lead, I know all submitted values, so this expression won't cause other problems
var disNN = dis.replace(/^0+/, '');
var disNN = number(dis)
Any of these, when included in my code, generate the following error:
Uncaught TypeError: undefined is not a function
This seems like it should be so simple....how can I get rid of that leading zero for values that are between 0 and 1?
Also, the array is generated from php with a call like this:
var distance = <?php echo json_encode($distance);?>;
in case that's relevant. Thanks for any advice.
The trick is in the message you are seeing
Uncaught TypeError: undefined is not a function
I'm not too sure how distance[i] is being instantiated; but my guess is that it is an int, not a string, so it does not have any of the built in string functions (like .replace).
You could try this:
var dis = distance[i].toString();
Please take care to make sure distance[i] isn't null, or 'toString fails and you're back to sqaure one.
I'd remove the leading zeroes using the php function ltrim and pass the distances well formatted to the javascript that generates the urls.
Usage:
$str = ltrim($str, '0');// Remove leading 0's
echo ltrim(00000.1, '0');// echoes .1
I'm trying to find an expression for JavaScript which gives me the two characters at a specific position.
It's always the same call so its may be not too complicated.
I have always a 10 char long number and i want to replace the first two, the two at place 3 and 4 or the two at place 5 and 6 and so on.
So far I've done this:
number.replace(/\d{2}/, index));
this replace my first 2 digits with 2 others digits.
but now I want to include some variables at which position the digits should be replaced, something like:
number.replace(/\d{atposx,atpox+1}/, index));
that means:
01234567891
and I want sometimes to replace 01 with 02 and sometimes 23 with 56.
(or something like this with other numbers).
I hope I pointed out what I want.
This function works fine:
function replaceChars(input, startPos, replacement){
return input.substring(0,startPos) +
replacement +
input.substring(startPos+replacement.length)
}
Usage:
replaceChars("0123456789",2,"55") // output: 0155456789
Live example: http://jsfiddle.net/FnkpT/
Numbers are fairly easily interpreted as strings in JS. So, if you're working with an actual number (i.e. 9876543210) and not a number that's represented by a string (i.e. '987654321'), just turn the number into a string (''.concat(number); ) and don't limit yourself to the constraints of what you can do with just numbers.
Both of the above examples are fine (bah, they beat me to it), but you can even think about it like this:
var numberString = ''.concat(number);
var numberChunks = numberString.match(/(\d{2})/g);
You've now got an array of chunks that you can either walk through, switch through, or whatever other kind of flow you want to follow. When you're done, just say...
numberString = numberChunks.join('');
number = parseInt(numberString, 10);
You've got your number back as a native number (or skip the last part to just get the string back). And, aside from that, if you're doing multiple replacements.. the more replacements you do in the number, the more efficient breaking it up into chunks and dealing with the chunks are. I did a quick test, and running the 'replaceChars' function was faster on a single change, but will be slower than just splitting into an array if you're doing two or more changes to the data.
Hope that makes sense!
You can try this
function replaceAtIndex(str,value,index) {
return str.substr(0,index)+value+str.substr(index+value.length);
}
replaceAtIndex('0123456789','X',3); // returns "012X456789"
replaceAtIndex('0123456789','XY',3); // returns "012XY56789"