regexp looping and logic in javascript - javascript

Not certain if this can be done in regexp under javascript, but thought it would be interesting to see if it is possible.
So thought I would clean up a piece of html to remove most tags, literally just dropping them, so <H1><img><a href ....>. And that would be relatively simple (well, stole the basis from another post, thanks karim79 Remove HTML Tags in Javascript with Regex).
function(inString, maxlength, callback){
console.log("Sting is " + inString)
console.log("Its " + inString.length)
var regex = /(<([^>]+)>)/ig
var outString = inString.replace(regex, "");
console.log("No HTML sting " + outString);
if ( outString.length < maxlength){
callback(outString)
} else {
console.log("Lets cut first bit")
}
}
But then I started thinking, is there a way where I can control regex execution. So lets say that I want to keep certain tabs, like b,br,i and maybe change H1-6 to b. So in pseudo code, something like:
for ( var i in inString.regex.hits ) {
if ( hits[i] == H1 ) {
hits[i] = b;
}
}
The issue is that I want the text thats not HTML tags to stay as it is, and I want it to just cut out by default. One option would of course be to change the ones I want to keep. Say change <b> to [[b]], once that is done to all the ones of interest. Then put them back to <b> once all unknown have been removed. So like this (only for b, and not certain the code below would work):
function(inString, maxlength, callback){
console.log("Sting is " + inString)
console.log("Its " + inString.length)
var regex-remHTML = /(<([^>]+)>)/ig
var regex-hideB = /(<b>)/ig
var regex-showB = /([b])/ig
var outString = inString.replace(regex-hideB, "[b]");
outString = outString.replace(regex-remHTML, "");
outString = outString.replace(regex-showB, "<b>");
console.log("No HTML sting " + outString);
if ( outString.length < maxlength){
callback(outString)
} else {
console.log("Lets cut first bit")
}
}
But would it be possible to be smarter, writing cod ethat says here is a peice of HTML tag, run this code against the match.

As Tim Biegeleisen sai in its comment, maybe a better solution could be using a parser instead of a Regex...
By the way, if you want to control what is going to be changed by the regex you can pass a callback to the String.prototype.replace:
var input = "<div><h1>CIAO Bello</h1></div>";
var output = input.replace(/(<([^>]+)>)/gi, (val) => {
if(val.indexOf("div") > -1) {
return "";
}
return val;
})
;
console.log("output", output);

Related

Can't get values past array[0] to translate properly

Okay, to start with I should mention this is a very small personal project, and I've only have a handful of coding classes several years ago now. I can figure out a lot of the (very) basics, but have a hard time troubleshooting. I'm in a little bit over my head here, and need a dumbed down solution.
I'm trying to put together a VERY simple translator that takes in a word or sentence from the user via a text input box, puts each word of the string into an array, translates each word in order, then spits out each translated word in the order it was input. For example, typing "I like cats" would output "Ich mag Katze" in German.
I've got most of it, but I CAN'T get anything but the first array element to translate. It comes out like "Ich like cats".
I've used a loop, probably because I'm an amateur and don't know another way of doing this, and I'd rather not use any libraries or anything. This is a very small project I want to have a couple of friends utilize locally; and I know there has to be some very simple code that will just take a string, put it into an array, swap one word for another word, and then output the results, but I'm damned if I can make it work.
What I currently have is the closest I've gotten, but like I said, it doesn't work. I've jerry-rigged the loop and clearly that's the totally wrong approach, but I can't see the forest for the trees. If you can help me, please make it "Javascript for Babies" picture book levels of simple, I cannot stress enough how inexperienced I am. This is just supposed to be a fun little extra thing for my D&D group.
function checkForTranslation(input, outputDiv) {
var input = document.getElementById("inputTextField").value;
var outputDiv = document.getElementById("translationOutputDiv");
input = input.toLowerCase();
//puts user input into an array and then outputs it word by word
const myArray = input.split(" "); //added .split, thank you James, still otherwise broken
let output = "";
let translation = "";
for (let i = 0; i < myArray.length; i++) {
output += myArray[i]; //up to here, this works perfectly to put each word in the string into an array
//prints all words but doesnt translate the second onwards
translation += myArray[i];
if (output == "") {
//document.getElementById("print2").innerHTML = "Translation Here";
}
else if (output == "apple") {
translation = "x-ray";
}
else if (output == "banana") {
translation = "yak";
}
else {
translation = "???";
}
output += " "; //adds a space when displaying original user input
} // END FOR LOOP
document.getElementById("print").innerHTML = output; //this outputs the original user input to the screen
document.getElementById("print3").innerHTML = translation; //this should output the translated output to the screen
} // END FUNCTION CHECKFORTRANSLATION
What it looks like
P.S. I'm not worried about Best Practices here, this is supposed to be a quickie project that I can send to a couple friends and they can open the HTML doc, saved locally, in their browser when they want to mess around with it if they want their half-orc character to say "die by my hammer!" or something. If you have suggestions for making it neater great, but I'm not worried about a mess, no one is going to be reading this but me, and hopefully once it's fixed I'll never have to read it again either!
Since it is a manual simple translation, you should just create a "dictionary" and use it to get the translations.
var dictionary = {
"apple": "x-ray",
"banana": "yak"
}
function checkForTranslation() {
var input = document.getElementById("inputTextField").value.toLowerCase();
var words = input
.split(' ') // split string to words
.filter(function(word) { // remove empty words
return word.length > 0
});
var translatedWords = words.map(function(word) {
var wordTranslation = dictionary[word]; // get from dictionary
if (wordTranslation) {
return wordTranslation;
} else { // if word was not found in dictionary
return "???";
}
});
var translatedText = translatedWords.join(' ');
document.getElementById("translationOutputDiv").innerHTML = translatedText;
}
document.getElementById('translate').addEventListener('click', function() {
checkForTranslation();
});
<input type="text" id="inputTextField" />
<button id="translate">translate</button>
<br/>
<hr />
<div id="translationOutputDiv"></div>
Or if you want it a little more organized, you could use
const dictionary = {
"apple": "x-ray",
"banana": "yak"
}
function getTranslation(string) {
return string
.toLowerCase()
.split(' ')
.filter(word => word)
.map(word => dictionary[word] || '???')
.join(' ');
}
function translate(inputEl, outputEl) {
outputEl.innerHTML = getTranslation(inputEl.value);
}
document.querySelector('#translate').addEventListener('click', function() {
const input = document.querySelector('#inputTextField');
const output = document.querySelector('#translationOutputDiv');
translate(input, output);
});
<input type="text" id="inputTextField" />
<button id="translate">translate</button>
<br/>
<hr />
<div id="translationOutputDiv"></div>

javascript : How to filter text without spell checking?

The goal is to filter some "test" or "flood" messages in a shout box chat.
ex: when an user writes something like
aaaaaaaaaaaaaaaaaaaaa or jdhshjdskhdshuishifhduif or dsqjlkdsqjiodsqjiosqjdsjq
I want to filter such stupid words: I guess I need to write some functions like:
if string length>20 or string conatins more that 4 vowels in a row or contains 4 consonants in a row
or contains some special chars...
Maybe this function has aleardy been written to avoid reinventing the wheel.
regards
Well using some Regular Expressions could do the trick.
EDIT
I have updated the code after Chris's suggestion.
So the credit goes to him.
String.prototype.testVowels = function () {
return !(/([aeiou]){4,}\w*/g.test(this));
}
String.prototype.testConsonants = function () {
return !(/([bcdfghjklmnpqrstwxyz]){4,}\w*/g.test(this));
}
String.prototype.testLength = function() {
return this.length < 20;
}
function testString(str) {
var stringArr = str.split(" ");
// this will test for each word in the str parameter
stringArr.forEach(function(s) {
if(s.testConsonants() && s.testLength() && s.testVowels()) {
console.log("The word " + s + " is ok !");
}
});
}

Unexpected Token Illegal with onclick Java Script in Salesforce.com

I have been working on this most of the morning but to no end. I am trying to execute a button that uses OnClick Java in Salesforce.com and it keeps throwing errors. I think the issue may be with special characters in the data as it works when I simply use just text. But any time numbers or any special characters are present I get the error "unexpected token ILLEGAL". Can anyone help me to see what I am doing wrong and how I can get away from failing when special characters are involved?
{!REQUIRESCRIPT("/soap/ajax/28.0/connection.js")}
var opptyObj = new sforce.SObject("Opportunity");
var caseObj = new sforce.SObject("Case");
var today = new Date();
var sOpptyId = "{!Case.Opportunity__c}";
if( sOpptyId != "")
{
alert("This case is already tied to an opportunity!");
}
else
{
opptyObj.AccountId = "{!Case.AccountId}";
opptyObj.CloseDate = sforce.internal.dateTimeToString(today);
opptyObj.Description="{!Case.Description}";
opptyObj.Case__c = "{!Case.Id}";
opptyObj.Name = "{!Case.Subject}";
opptyObj.StageName = "Estimate in Progress";
opptyObj.Created_from_Case__c = "Y";
opptyObj.Type = "New Business";
opptyObj.Amount = ".01";
var opptyresult = sforce.connection.create([opptyObj]);
if (opptyresult[0].success=='false')
{
alert("Opportunity creation failed: " + opptyresult[0].errors.message);
}
else
{
caseObj.Id = '{!Case.Id}';
caseObj.Opportunity__c = opptyresult[0].id;
caseObj.Status = "Estimate in Progress";
var caseResult = sforce.connection.update([caseObj]);
if(caseResult[0].success == 'false')
{
alert("Case update failed: " + caseResult[0].errors.message);
}
else
{
alert("An opportunity has been created and linked to this case.");
location.reload(true);
}
}
}
Assuming this is some kind of template, whatever is rendering this needs to properly escape some values in the strings it's inserting.
Given this:
opptyObj.Description="{!Case.Description}";
Let's say I enter a description consisting of this:
"That is awesome," said John.
When that is rendered in your template the result is this:
opptyObj.Description=""That is awesome," said John.";
As you might be able to see, the result is a syntax error.
You need to escape quote characters in an text inserted this way. And without knowing what is technology rendering this template I can't give you any specifics, but you want to replace " with \" and ' with \'. The \ escapes characters, forcing them to be treated as literal characters in the string instead of other special meaning.
This must be done as it's being inserted into the script. Something in the spirit of this:
opptyObj.Description="{!Case.Description.replace(/'/, "\\'").replace(/"/, '\\"')}
Exactly how to do that depends on what language or template engine is being used here. But th eresult should look like this:
opptyObj.Description="\"That is awesome,\" said John.";
Ruby on Rails implements an escape_javascript method, which sanitizes data for injection into Javascript. It does the following replacements. It seems like a good baseline.
'\\' => '\\\\'
'</' => '<\/'
"\r\n" => '\n'
"\n" => '\n'
"\r" => '\n'
'"' => '\\"'
"'" => "\\'"
UPDATE:
According to this: http://www.salesforce.com/us/developer/docs/pages/Content/pages_security_tips_scontrols.htm
It looks like you want the JSENCODE function. Something like this, perhaps?
opptyObj.Description="{!JSENCODE(Case.Description)}";

Word count is wrong when adding new line in contenteditable

I count the words in a contenteditable. I split it using spaces. The problem comes when you enter a new line. It doesn’t count the word you’re currently writing on the new line until you add a space.
On top of that, in the following example if you split the example text into two lines, it will “eat up” one word when you do that:
http://jsfiddle.net/MrbUK/
I’m guessing this issue exists because between HTML elements there are no spaces:
<div>some things</div><div>are cool</div> its string would be “some thingsare cool”.
Here’s the code that I have:
function wordCount() {
var content_text = $('#post_content').text(),
char_count = content_text.length,
word_count = 0;
// if no characters, words = 0
if (char_count != 0)
word_count = content_text.replace(/[^\w ]/g, "").split(/\s+/).length;
$('.word_count').html(word_count + " words • " + char_count + " characters");
}
I tried replacing some HTML tags:
word_count = content_text.replace(/ /g, " ").replace(/<div>/g, "<p>").replace(/<\/div>/g, "</p>").replace(/<\/p><p>/g, " ").split(/\s+/).length;
without any luck. I need to discard whether it’s a <p> or <div> and some browsers add when merging lines together.
Any ideas? Thanks!
EDIT:
Thanks to Jefferson below for his clever method, I managed to solve this. For some reason I have to do -1 on the word_count to display the correct number of words:
function wordCount() {
var content_div = $('#post_content'),
content_text,
char_count = content_div.text().length,
word_count = 0;
// if no characters, words = 0
if (char_count != 0)
content_div.children().each(function(index, el) {
content_text += $(el).text()+"\n";
});
// if there is content, splits the text at spaces (else displays 0 words)
if (typeof content_text !== "undefined")
word_count = content_text.split(/\s+/).length - 1;
$('.word_count').html(word_count + " words • " + char_count + " characters");
}
You can use this:
$("#post_content").children().each(function(index, el){buffer += $(el).text()+"\n"})
This way you iterate by all elements inside your div and get only the text, put a "\n" between them.
Jefferson's answer was great, and it helped me with this exact same issue.
The problem I encountered was the contents of my contenteditable div was not entirely wrapped in HTML tags.
For example, my div contained the following HTML code:
This is my first line<div>This is my second line</div>
By using $.children(), it was ignoring the first line and only returning a word count of 5. To get round this I used $.contents() instead. Modified code is below:
$("#post_content").contents().each(function(index, el){buffer += $(el).text()+"\n"})
This returned a line count of 10.
Apologies for adding this as an answer and not as a comment to Jefferson's answer, however my reputation is too low to allow me to do that. I felt it was worth pointing the above out though.

eval javascript function IE6 taking long time

I have the below chunk of code. I've debugged through and located the snippet that is causing a long delay in IE6.
Basically the code loops through a document converting it to XML and sending to a PDF. On Ubuntu and Firefox 4 it takes 3 seconds. On IE it can take up to 40 seconds regularly.
/**
* This function builds up the XML to be saved to the DM.
*/
function getXMLToSave(){
var text="<workbook><sheet><name>Adv4New</name>";
//show_props(document.adv4.row10col1, "document.adv4.row10col1");
for(i=1;i<157;i++){
text = text + "<row number='" + i + "'>";
for(j=1;j<=7;j++){
text = text + "<col ";
//alert(eval('document.adv4.row'+i+'col'+j+'.readonly'));
try{
text = text + "number='" + j + "' label='" + eval('document.adv4.row'+i+'col'+j+'.className')+ "'";
}
catch (e) {
text = text + "number='" + j + "' label=''";
}
try {
if(eval('document.adv4.row'+i+'col'+j).readOnly)
text = text + " type='readonly'";
else
text = text + " type=''";
}
catch (e) {
text = text + " type=''";
}
try {
text = text + " color='" + eval('document.adv4.row'+i+'col'+j+'.style.color') + "'";
}
catch (e) {
text = text + " color=''";
}
text = text + ">";
try {
// don't wrap in a CDATA (like previously), but run cleanNode
// this fixes html entities
var content = eval('document.adv4.row'+i+'col'+j+'.value');
text = text + cleanNode(content);
}
catch (e) {
text = text + "0";
}
text = text + "</col>";
}
text = text + "</row>";
}
text = text + "</sheet></workbook>";
return text;
}
I believe its the eval function causing the delay in IE6. Is there a neat solution to fix this. Thanks very much
Why are you using eval in the firts place?
eval('document.adv4.row'+i+'col'+j+'.style.color')
Use bracket notation!
document.adv4["row"+i+"col"+j].style.color
You don't need eval() at all:
text = text + "number='" + j + "' label='" + document.adv4['row' + i + 'col' + j].className + "'";
Also, in IE6 (but not in newer browsers), building up large strings by repeatedly adding more content is really, really slow. It was way faster in that browser to build up strings by creating an array of substrings and then joining them all together when finished with all the pieces.
Don't use eval EVAL is EVIL. Having said that, you really shouldn't care about IE6: Even MS doesn't support it any longer, why should you bother?
Anyhow, change all eval calls like:
eval('document.adv4.row'+i+'col'+j+'.value');
to
document.adv4['row' + i + 'col' + j].value;
To access the elements directly. Remember that Nodes are objects, so their properties can be accessed either using the dot-notation (foo.bar) or the "associative array" notation: foo['bar'], the latter being very useful when you need the value of a variable to access properties
Don't use eval - period. The eval() should be renamed to evil(). There is almost no situation where you really need to use the eval function.
In this case you can use document.getElementById() to find a DOM node with a specific id.
It's likely that it's all the string concatentation that makes it slow. Each time you add something to the text, it will copy all the previous text into a new string.
Newer browsers have optimised code for this special case, so for them the impact is less.
Instead of concatenating strings like this:
text = text + "something";
use an array instead:
var text = [];
then add items to the array using the push method:
text.push("<workbook><sheet><name>Adv4New</name>");
Finally just join the strings together:
return text.join('');
One solution could be generating a color array (or maybe an object if you need it) and then using it.
But then, ask yourself the question "Should I really support IE6?"

Categories

Resources