JavaScript string modification (Probably involves regular expression) - javascript

The problem I need to solve is to shorten file paths given by the user. If you didn't know, sometimes it's not possible to enter in paths with spaces in the command prompt. You are required to either put the path in quotes or rename the paths with spaces to "abcdef~1".
Example: "C:\Some Folder\Some File.exe" should become "C:\SomeFo~1\SomeFi~1.exe" (case insensitive).
I'm making a function in JavaScript to attempt to shorten file paths using this idea.
function ShortenFilePath(FilePath){
var Sections = FilePath.split("\\")
for (Index = 0; Index < Sections.length; Index++){
while (Sections[Index].length > 6 && Sections[Index].match(" ") && !Sections[Index].match("~1")){
alert(Sections[Index])
Sections[Index] = Sections[Index].replace(" ","")
Sections[Index] = Sections[Index].substring(0,6)
Sections[Index] = Sections[Index] + "~1"
alert(Sections[Index])
}
}
var FilePath = Sections.join("\\")
alert(FilePath)
return FilePath
}
The problem is, it will leave out the file extension and spit out "C:\SomeFo~1\SomeFi~1". I need help obtaining that file extension (probably through regular expression). If you feel that this function can be optimized, please do share your thoughts.
UPDATE: I believe the problem has been resolved.
UPDATE 2: There were some problems with the previous code, so I revised it a little.
UPDATE 3: Fresh new problem. Yikes. If the name of the file itself without the extension is under 7 letters, then it will turn up as "name.e~1.exe".
UPDATE 4: I think I've finally fixed the problem. I THINK.
function ShortenFilePath(FilePath){
var Sections = FilePath.split("\\")
Sections[Sections.length - 1] = Sections[Sections.length - 1].substring(0,Sections[Sections.length - 1].lastIndexOf("."))
for (Index = 0; Index < Sections.length; Index++){
while (Index > 0 && Sections[Index].match(" ") && !Sections[Index].match("~1")){
Sections[Index] = Sections[Index].replace(/ /gm,"")
Sections[Index] = Sections[Index].substring(0,6) + "~1"
}
}
return Sections.join("\\") + FilePath.substring(FilePath.lastIndexOf("."))
}

I would use this to get the extension:
someString.substring(someString.lastIndexOf("."))
you also asked for some code review, so:
1 - Your JS conventions are a little off, it looks more like C# :) Why the capital letter in variable and method names?
2 - You said you can go with the quotes option instead of using ~1, seems easier, why did you decide not to?
3 - Why do you need something like this in your JS?

How about this:
function ShortenFilePath(FilePath){
var Sections = FilePath.split("\\")
var suffix = FilePath.match(/(\..*$)/)
for (Index = 0; Index < Sections.length; Index++){
while (Sections[Index].length > 6 && Sections[Index].match(" ") && !Sections[Index].match("~1")){
alert(Sections[Index])
Sections[Index] = Sections[Index].replace(" ","")
Sections[Index] = Sections[Index].substring(0,6)
Sections[Index] = Sections[Index] + "~1"
alert(Sections[Index])
}
}
var FilePath = Sections.join("\\") + (suffix? suffix[1] : '')
alert(FilePath)
return FilePath
}

You could use String.prototype.replace with a callback:
function ShortenFilePath(FilePath){
return FilePath.replace(/([^:\\]+)([\\|\.[^\\]+)/g, function(text,match1, match2){
return match1.length > 8 ? match1.replace(' ', '').substr(0, 6) + '~1' + match2 : match1.replace(' ', '') + match2;
});
}
I am not 100% sure that this will output excactly what you need but probably you get the idea :)
jsFiddle

Fix for Update #3 problem:
if (FilePath.lastIndexOf(".") > 6){
Sections[Index] = Sections[Index].substring(0,6) + "~1"
} else {
Sections[Index] = Sections[Index].substring(0, FilePath.lastIndexOf(".")) + "~1"
}
And btw, this:
while (Sections[Index].match(" ")){
Sections[Index] = Sections[Index].replace(" ","")
}
Should probably look like this:
Sections[Index] = Sections[Index].replace(/ /gm, "");

Related

Problems with IF condition

I'm trying to make a website that gathers information from APIs. The following code always evaluates to 'Beep Boop Beep! I can\t find the Wikipedia page with the API! :-( \n Anyways here is more info on...'! Anyone have any ideas why?
var geoNamesWiki = result.geoNamesWiki;
for (let j = 0; j < 30; j++) {
if (geoNamesWiki.geonames[j].feature == 'country' &&
(geoNamesWiki.geonames[j].countryCode == openCage.results[0].components["ISO_3166-1_alpha-2"] ||
geoNamesWiki.geonames[j].title.includes(openCage.results[0].components.country))) {
$('#summary').html(geoNamesWiki.geonames[j].summary);
$('#wikiLink').html(geoNamesWiki.geonames[j].wikipediaUrl).attr("href", "https://" + geoNamesWiki.geonames[j].wikipediaUrl);
} else {
$('#summary').html('Beep Boop Beep! I can\t find the wikipedia page with the API! :-( \n Anyways here is more info on' + openCage.results[0].components.country + ':');
$('#wikiLink').html('https://en.wikipedia.org/wiki/' + encodeURI(openCage.results[0].components.country)).attr("href", 'https://en.wikipedia.org/wiki/' + encodeURI(openCage.results[0].components.country));
}
}
Is suspect you have a string there at var geoNamesWiki = result.geoNamesWiki;
Try parsing it to a JSON object first var geoNamesWiki = JSON.parse( result.geoNamesWiki );
I found the answer thanks to #Bekim Bacaj! I was overwriting what I had already done, so just needed to add a break on the final line of the IF part.

How do I mask an email address between the first and the last character before the # sign?

My goal is to edit the string (which has an email) to mask the first part, like say the email is johndoe#abc.com then I should output j*****e#abc.com.
var maskPII = function(S) {
var ans = "";
if(S.includes("#")){
S = S.toLowerCase();
var parts = S.split("#");
var first = parts[0];
for(var i=0;i<parts[0].length;i++){
if(i!=0 && i!=parts[0].length - 1)
first[i] = '*';
}
ans = first +"#" +parts[1];
}else{
}
return ans;
};
However in my loop I can't change the characters to asterisks.
After execution I see value of first still same as parts[0] and has no asterisks, can some one explain why? Also, what would I need to do to modify the variable inside loop?
To answer your question... javascript allows you access values of a string using [] indexing.. but that is read only access... you cannot insert/replace values using that operator.
Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
When using bracket notation for character access,
attempting to delete or assign a value to these properties will not succeed.
The properties involved are neither writable nor configurable.
(See Object.defineProperty() for more information.)
You need to extract the values you want to keep from the existing string and build up a new string as noted in other answers...
Well, this's what you're looking for, and this will be the output j*****e#abc.com.
var ans = "";
var S = "johndoe#abc.com"; //example
S = S.toLowerCase();
var parts = S.split("#");
var first = "";
for(var i = 0; i < parts[0].length; i++){
if(i != 0 && i != parts[0].length - 1){
first += '*';
}else{
first += parts[0][i];
}
}
ans = first +"#"+ parts[1];
console.log(ans);
Here is the code with your approach:
var maskPII = function(S) {
var ans = "";
if(S.includes("#")){
S = S.toLowerCase();
var parts = S.split("#");
var first = parts[0][0];
for(var i=0;i<parts[0].length;i++){
if(i!=0 && i!=parts[0].length - 1)
first += '*';
}
ans = first + parts[0][parts[0].length - 1] +"#" +parts[1];
}else{
}
return ans;
};
But if i were you i would use:
var mail = "johndoe#abc.com";
mail = mail.replace(/(?<=.)(.+?)(?=.#)/gi, '*'.repeat(mail.split('#')[0].length - 2));
console.log(mail);
You can use the bracket notation on a string (like an array) to get the character at a specific index, but you can't use this to change characters. So first[i] = '*' in your code wont do anything.
Strings in JavaScript are immutable. This means that if you want to change a string, a new string instance will be created. This also means that when you change a string in a for-loop, it can impact performance. (Although in this case the difference wont be noticeable.
)
I would use this code:
function maskPII(str) {
const indexOfAt = str.indexOf('#');
if (indexOfAt <= 2) {
return str;
}
return str[0] + '*'.repeat(indexOfAt - 2) + str.substring(indexOfAt - 1);
}
const email = 'johndoe#abc.com';
console.log(email);
console.log(maskPII(email));
It will look for the index of the # sign. If the index is less or equal than 2, (when not found the index will be -1) it will return the original string.
Otherwise it will get the first character, calculate the amount of asterisks needed (index of the # sign -2) and repeat those and then add the rest of the original string.

Phonegap Hide Backend URL link code

I have been creating Phonegap apps. I searched the web as well as here to find that there is no way you can hide your code for Phonegap apps.
I do use obfuscation and that serves the purpose of protecting the code somewhat.
Is there a way to hide the back-end API URL links that I am using?
The links to the server are still available even after obfuscation.
Is there a way to do this? or a work around?
I have used this algorithm, and adjusted it for my own purpose, but lets take this one as an example:
http://www.mvjantzen.com/blog/?p=1005
U have your key
var key = function () {
return 'SXGWLZPDOKFIVUHJYTQBNMACERxswgzldpkoifuvjhtybqmncare';
};
Decrypt
var _decodeStr = function(coded) {
coded = decodeURIComponent(coded);
var uncoded = '';
var chr;
for (var i = coded.length - 1; i >= 0; i--) {
chr = coded.charAt(i);
uncoded += (chr >= 'a' && chr <= 'z' || chr >= 'A' && chr <= 'Z') ?
String.fromCharCode(65 + key().indexOf(chr) % 26) :
chr;
}
return uncoded.toLowerCase();
};
Encrypt
var _encodeStr = function(uncoded) {
uncoded = uncoded.toUpperCase().replace(/^\s+|\s+$/g,'');
var coded = '';
var chr;
for (var i = uncoded.length - 1; i >= 0; i--) {
chr = uncoded.charCodeAt(i);
coded += (chr >= 65 && chr <= 90) ?
key.charAt(chr - 65 + 26*Math.floor(Math.random()*2)) :
String.fromCharCode(chr);
}
return encodeURIComponent(coded);
}
var encodedUrl = _encodeStr('http://www.whateverul.com/api/call/');
_decodeStr(encodedUrl); // fake encrypted url
so the url that u got encode, u can use wherever u wanna use it, just call it with the decoder,
Remove the encoder from your source files.
This give u somewhat of a way for people when they are searching tru your code for generic lines like http:/// or api.bla.com/call or whatever, its harder to find.
But u cannot totally hide it, this just makes it a little bit harder, i use this method in my phonegap apps, i also don't use clear function names, don't name your function encryptedUrlDecoder() or something:P
and even if u do, they can always sniff the outgoing calls etc, but this helps a bit (atleast when somebody is reverse engeneering your code)
after encrypting obfuscate/minimize your js code, to make it even more complex to read
i hope this helps u a bit :) good luck!

Regex not correctly matching

Please do not be alarmed at the huge walls of text. This is not a very expert question and does not require much reading.
Problem:
I have a group of regexes in an array that are ran through and go through a string, matching and wrapping text around the match.
I am having a lot of problems with this and I have no clue why. Most of my regexes are not matching correctly with this string:
var changelog = `+ = Added
- = Removed
~ = Changed
[line]
v1 - 4chan Enhancer is released
[line]
v2 - Minor update
Added support for new settings in the future
[line]
v3 - Major update
+ Infinite scrolling
+ Remove ads completely
+ Fetch replies automatically
+ Remove comic at top
+ Random Pepe
+ Blocked keywords
+ Changelog
+ Version
[line]
If you would like to request more features, please email me at billy#billyvenner.co.uk`;
If I run the regexes, the function returns this:
<span style='color: #009<span style='color: #009110'>1</span>10'>+</span> = Added
<span style='color: #FF0000'>-</span> = Remo<span style='color: #009110'>v</span>ed
~ = Changed
[line]
v1 - 4chan Enhancer is released
[line]
v2 - Minor update
Added support for new settings in the future
[line]
v3 - Major update
+ Infinite scrolling
+ Remove ads completely
+ Fetch replies automatically
+ Remove comic at top
+ Random Pepe
+ Blocked keywords
+ Changelog
+ Version
[line]
If you would like to request more features, please email me at billy#billyvenner.co.uk
4chan Enhancer v3
Observing the new changelog using regex101 and running my regexes through it, I am returned with exactly what I'm trying to match.
For some odd reason, all of them only get matches once or zero times. Here's the array that the regexes are in:
var formats = [
["^(\\+).*","<span style='color: #009110'>","</span>"],
["^\[line\]","<hr>","",false],
["^(\\~).*","<span style='color: #0086E0'>","</span>"],
["^(\\-).*","<span style='color: #FF0000'>","</span>"],
["^(v[0-9]+).*","<span style='color: #009110'>","</span>"],
["(http[s]{0,1}:\\/\\/www\\.[a-zA-Z0-9]*\\.[a-zA-Z0-9]*\\.[a-zA-Z0-9]*(?:\\/|-|_|=|\\?|&|[a-zA-Z0-9])*)",linkify],
["((?:\\/|-|_|=|\\?|&|[a-zA-Z0-9])*#(?:\\/|-|_|=|\\?|&|[a-zA-Z0-9])*\\..*\\.(?:\\/|-|_|=|\\?|&|[a-zA-Z0-9])*)",function() {linkify("mailto")}],
];
If you try running these regexes through my changelog, it works fine.
Please note with the above regexes: you can see the double backslashes because of the escaping character in JavaScript (so they are actually just one backslash in the actual regex) and the two regexes at the bottom are being implemented later and currently do nothing in my code.
Here is the actual code to run through these regexes:
function linkify(before) {
}
function colorChangelog() {
var newChangelog = "";
newChangelog = changelog;
var formats = [
["^(\\+).*","<span style='color: #009110'>","</span>"],
["^\[line\]","<hr>","",false],
["^(\\~).*","<span style='color: #0086E0'>","</span>"],
["^(\\-).*","<span style='color: #FF0000'>","</span>"],
["^(v[0-9]+).*","<span style='color: #009110'>","</span>"],
["^(http[s]{0,1}:\\/\\/www\\.[a-zA-Z0-9]*\\.[a-zA-Z0-9]*\\.[a-zA-Z0-9]*(?:\\/|-|_|=|\\?|&|[a-zA-Z0-9])*)",linkify],
["^((?:\\/|-|_|=|\\?|&|[a-zA-Z0-9])*#(?:\\/|-|_|=|\\?|&|[a-zA-Z0-9])*\\..*\\.(?:\\/|-|_|=|\\?|&|[a-zA-Z0-9])*)",function() {linkify("mailto")}],
];
for (y = 0; y < formats.length; y++) {
console.log(y);
var leregex = new RegExp(formats[y][0],"g")
var executed2 = leregex.exec(newChangelog);
if (!!leregex.exec(newChangelog)) {
if (!!leregex.exec(newChangelog)[1]) {
var executed = executed2[1];
for (match = 0; match < executed.length; match++) {
if (typeof(formats[y][1]) == "string") {
if (formats[y][formats[y].length-1] != false) {
var newstr = formats[y][1] + executed[match] + formats[y][2];
newChangelog = newChangelog.replace(executed[match],newstr);
} else {
var newstr = formats[y][1] + formats[y][2];
newChangelog = newChangelog.replace(executed[match],newstr);
}
} else {
if (typeof(formats[y][1]) == "function") {
} else {
console.log("Invalid 2nd argument: " + formats[y][1]);
}
}
}
}
}
console.log(newChangelog);
}
changelog = newChangelog + `
4chan Enhancer ` + version;
};
colorChangelog();
console.log(changelog);
I am using new RegExp to run my regexes with the flags "gm" with the g meaning it will match as much as possible and the m meaning it will start ^s and $s at the start/end of the line.
Thank you for reading this huge daunting block of text, I hope you can help.
Your issue is with your usage of exec. .exec() will return the first matched instance not yet returned. Drop the exec into a while loop and you should get what you need. You need to make sure you dont have anything inside the loop that will turn this into an infinite issue. changing your for loop to the following appears to work:
for (y = 0; y < formats.length; y++) {
//console.log(y);
var leregex = new RegExp(formats[y][0], "gm")
while (!!(executed2 = leregex.exec(newChangelog))) {
//console.log(executed2)
if (!!executed2[1]) {
if (typeof(formats[y][1]) == "string") {
if (formats[y][formats[y].length - 1] != false) {
var newstr = formats[y][1] + executed2[0] + formats[y][2];
newChangelog = newChangelog.replace(executed2[0], newstr);
} else {
var newstr = formats[y][1] + formats[y][2];
newChangelog = newChangelog.replace(executed2[0], newstr);
}
} else {
if (typeof(formats[y][1]) == "function") {
} else {
console.log("Invalid 2nd argument: " + formats[y][1]);
}
}
}
}
//console.log(newChangelog);
}
I instantiated executed2 at the top of the function:
var newChangelog = "", executed2;
Uncomment the console.logs to see the states scroll by.
You might want to rename some of the vars to make more sense (specifically the executed2 var, as executed no longer exists
I used this reference from developer.mozilla.org for info on .exec

How to do Initial Caps With Javascript/jQuery

I have a Dynamic Breadcrumb set up with JavaScript. All I want is to do Initial Caps for each word.
Example:
Home > Some > Page
Currently I have them all converted to lowercase and have removed all - from the strings in pages that have multiple words. I just need to convert the string to Initial Caps. Here is my code that I have working so far:
var path = "",
href = document.location.href,
domain = href.match(/:\/\/(.[^/]+)/)[1],
replacedomain = 'http://' + domain + '/',
s = href.replace(/-/gi, " ").split("/"),
lastElement = document.location.href.split('/').splice(-1,1);
for (var i = 2; i < (s.length - 1); i++) {
path += "<a class='bc' href=\"" + href.substring(0, href.indexOf("/" + s[i]) + s[i].length + 1) + "/\">" + s[i] + "</a> > ";
if (i > 0) {
breadcrumb = path;
}
}
i = s.length - 1;
breadcrumb += "<span>" + s[i] + "</span>";
var breadcrumbl = breadcrumb.toLowerCase(),
domain = breadcrumbl.match(/:\/\/(.[^/]+)/)[1],
breadcrumb2 = breadcrumbl.replace(domain, "").replace(domain, ""),
breadcrumbs = breadcrumb2,
url = 'Home' + breadcrumbs;
document.getElementById('breadcrumb1').innerHTML=url;
I think the solution is with a regular expression but I'm not good at writing them and I'm having a hard time with the concept. Also if anyone thinks this script can be optimized further your feedback is welcome. I'll will make variable names more semantic for production.
You could use css:
span.breadcrump {
text-transform: capitalize;
}
I recently wrote this helper method to do this for me:
function autocase ( text ) {
return text.replace(/(&)?([a-z])([a-z]{2,})(;)?/ig,function ( all, prefix, letter, word, suffix ) {
if (prefix && suffix) {
return all;
}
return letter.toUpperCase() + word.toLowerCase();
});
}
It takes into account things such as ™
Edit: To use this method, simply pass it a string, and it will return the string auto cased. It does not work on html strings.
//...
document.getElementById('breadcrumb1').innerHTML=url;
function autocase ( text ) {
return text.replace(/(&)?([a-z])([a-z]{2,})(;)?/ig,function ( all, prefix, letter, word, suffix ) {
if (prefix && suffix) {
return all;
}
return letter.toUpperCase() + word.toLowerCase();
});
}
$("#breadcrumb1 a").text(function(i,text){
return autoCase(text);
});
Try using css property text-transform:capitalize; for the breadcrumb.
Mostlikely in you case it should be,
.breadcrumb1 a {
text-transform: capitalize;
}
My first thought is:
breadcrumb += "<span>" + s[i].substring(0,1).toUpperCase() + s[i].substring(1) + "</span>";
But #Esailija's answer is much easier.
Reference:
toUpperCase().
not to be a punk but why not just use css?
text-transform: capitalize;
Sorry if you really need JS but in CSS you can easily use text-transform:Capitalize;
Since the accepted answer didn't actually answer the question as it was asked, I figured this might help; it's a solution using Regex with JavaScript, originally found here: Regex capitalize first letter every word
Here's the snippet I found useful:
var re = /(\b[a-z](?!\s))/g;
var s = "fort collins, croton-on-hudson, harper's ferry, coeur d'alene, o'fallon";
s = s.replace(re, function(x){return x.toUpperCase();});
console.log(s); // "Fort Collins, Croton-On-Hudson, Harper's Ferry, Coeur D'Alene, O'Fallon"
Here's one:
s.replace(/(^[a-zA-Z]{1})/,function (s){
return s.toUpperCase();
});

Categories

Resources