Javascript pig latin regex not working - javascript

Trying to make a function that will convert English words into Pig Latin. The problem I have is when I check to see if the first letter is a vowel. I check using a regular expression: if (str[0] === /[aeiou]/i) but it doesn't work. Something is wrong with my regex but I look at references and it seems like that should work. I don't know what's going on. Can someone explain why the regex I am using does not work and what would be a similar working solution? If you run the code below, it doesn't give the right result, just saying beforehand.
function translate(str) {
var tag = "";
if (str[0] === /[aeiou]/i) {
tag = "way";
return str + tag;
}
else {
var count = 0;
for (var i = 0; i< str.length; i++) {
if (str[i] !== /[aeiou]/i)
tag += str[i];
else
break;
count = i;
}
console.log(count);
return str.slice(count + 1) + tag + "ay";
}
}
So when I run say translate(overjoyed) it should return "overjoyedway". And if I run translate(glove) it should return "oveglay".

What you have written is not the way you use regular expressions. The code if (str[0] === /[aeiou]/i) tests whether the first element of the str string array is both equal value and equal type as the regular expression: /[aeiou]/i. Characters are not the same type as regular expressions, so such a comparison will evaluate to false.
Think of the regular expression as a tool that can be used to search an entire string array for a match (all of str, not just str[0]). The web has a bunch of great examples, but to get you started, you might try using str.search(regexp) which will return the index of the first match (if found) or -1 (if no match).
Your code then becomes (without too much deviation from the original, and without trying to be clever or optimal):
function translate(str) {
var tag = "";
var pos = str.search(/[aeiou]/i); // This is ONE way to use regular expressions.
if (pos == 0) { // First letter is a vowel.
tag = "way";
return str + tag;
} else if (pos > 0) { // Some letter (not the first) is a vowel.
// Instead of the loop checking each element, we already know where
// the match is found: at position = pos.
console.log(pos); // Log the match position of the first vowel.
tag = str.slice(0, pos); // The string before the first vowel.
return str.slice(pos) + tag + "ay";
}
}

This works
function pig(str) {
if (/^[aeiou]/i.test(str)) {
return str + 'way';
}
else {
return str.replace(/^(.[^aeiou]+)([aeiou].*)$/i, "$2$1ay");
}
}
console.log(pig('overjoyed'));
console.log(pig('glove'));

I know this is old, but I just recently did something similar in Ruby and thought I'd rewrite in in JavaScript and supply it as an answer.
function translate( words )
{
return words.split(' ').map(function(word){
return word.split(/\b([^a,e,i,o,u]{0,}qu|[^a,e,i,o,u]+)?([a,e,i,o,u][a-z]+)?/i).reverse().join('') + 'ay'
}).join(' ')
}
So in mine I take a string words that can be a single word or a full sentence.
I split it up into an array of words by splitting on spaces.
I then used map to run code on each word in that array, in there I have it split the word using my regex (which I'll explain at the end) which splits it into the first sound if it is anything other than a vowel sound and the rest of the word.
On the word quiet that split actually results in the following array: ["","qu","iet",""], and on the word aqua it results in ["",undefined,"aqua",""].
I can ignore those undefined and empty strings though because when we join it back together they get ignored.
So after it is split up I reverse the array and then join it back together as a word (joining it using an empty string '') and then tack on 'ay' to the end of the resulting string.
Now to explain the regex:
\b says we are looking for the start of a word, it could alternatively be ^ for the start of the string.
([^a,e,i,o,u]{0,}qu|[^a,e,i,o,u]+)? is an optional capture group looking for that first consonant sound, let's further break it up.
So within it we have two alternatives we are looking for, either [^a,e,i,o,u]{0,}qu or [^a,e,i,o,u]+, the first one checks for the first sound containing qu with or without preceding non-vowel characters (so the qu from quiet, or the squ from square get matched instead of stopping before the u), and the second one is checking for all non-vowel letters before the first vowel in the case that there is no qu at the start.
Now that final part of it ([a,e,i,o,u][a-z]+)? is just grabbing from that first vowel on as the rest of that match
I hope someone somewhere finds this useful :)

function translatePigLatin(str) {
if(["a","e","i","o","u"].indexOf(str[0])!==-1){
str+="way";
}else{
while(["a","e","i","o","u"].indexOf(str[0])==-1){
str+=str[0];
str=str.slice(1);
}
str+="ay";
}
return str;
}
translatePigLatin("glove");
this works:
1.check the string's first letter .if the letter is vowel then is easy for us to complete the word with "way"
2.if the first letter is not vowel,remove the first letter to end.
repeat the loop until the "first" letter is vowel.
3.now the string have changed and we add an another string("ay") to the string's end

Related

Removing all special characters except "some" apostrophes

I'm trying to create a function that removes all special characters (including periods) except apostrophes when they are naturally part of a word. The regex pattern I've made is supposed to remove anything that doesn't fit the schema of word either followed by an apostrophe ' and/or another word:
function removeSpecialCharacters(str) {
return str.toLowerCase().replace(/[^a-z?'?a-z ]/g, ``)
}
console.log(removeSpecialCharacters(`I'm a string.`))
console.log(removeSpecialCharacters(`I'm a string with random stuff.*/_- '`))
console.log(removeSpecialCharacters(`'''`))
As you can see from the snippet it works well except for removing the rogue apostrophes.
And if I add something like [\s'\s] or ['] to the pattern it breaks it completely. Why is it doing this and what am I missing here?
Alternate the pattern with '\B, which will match and remove apostrophes which are not followed by a word character, eg ab' or ab'#, while preserving strings like ab'c:
function removeSpecialCharacters(str) {
return str.toLowerCase().replace(/'\B|[^a-z'? ]/g, ``)
}
console.log(removeSpecialCharacters(`I'm a string.`))
console.log(removeSpecialCharacters(`I'm a string with random stuff.*/_- '`))
console.log(removeSpecialCharacters(`'''`))
(you can also remove the duplicated characters from the character set)
Not sure what went wrong with yours as I can't see what you attempted. However, I got this to work.
function removeSpecialCharacters(str) {
str = str.toLowerCase();
// reduce duplicate apostrophes to single
str = str.replace(/'+/g,`'`);
// get rid of wacky chars
str = str.replace(/[^a-z'\s]/g,'');
// replace dangling apostrophes
str = str.replace(/(^|\s)'(\s|$)/g, ``);
return str;
}
console.log(removeSpecialCharacters(`I'm a string.`))
console.log(removeSpecialCharacters(`I'm a string with random stuff.*/_- '`))
console.log(removeSpecialCharacters(`'''`))
console.log(removeSpecialCharacters(`regex 'til i die`))
Here's one very easy solution. To remove certain characteristics from a string, you can run a bunch of if-statements through a while loop. This allows you to chose exactly which symbols to remove.
while (increment < string.length)
{
if (string[increment] == "!")
}
delete "!";
}
increment += 1;
}
That's a simple rundown of what'll look like (not actual code) to give you a sense of what you're doing.

Capitalize the first letter of each word

var name = "AlbERt EINstEiN";
function nameChanger(oldName) {
var finalName = oldName;
// Your code goes here!
finalName = oldName.toLowerCase();
finalName = finalName.replace(finalName.charAt(0), finalName.charAt(0).toUpperCase());
for(i = 0; i < finalName.length; i++) {
if (finalName.charAt(i) === " ")
finalName.replace(finalName.charAt(i+1), finalName.charAt(i+1).toUpperCase());
}
// Don't delete this line!
return finalName;
};
// Did your code work? The line below will tell you!
console.log(nameChanger(name));
My code as is, returns 'Albert einstein'. I'm wondering where I've gone wrong?
If I add in
console.log(finalName.charAt(i+1));
AFTER the if statement, and comment out the rest, it prints 'e', so it recognizes charAt(i+1) like it should... I just cannot get it to capitalize that first letter of the 2nd word.
There are two problems with your code sample. I'll go through them one-by-one.
Strings are immutable
This doesn't work the way you think it does:
finalName.replace(finalName.charAt(i+1), finalName.charAt(i+1).toUpperCase());
You need to change it to:
finalName = finalName.replace(finalName.charAt(i+1), finalName.charAt(i+1).toUpperCase());
In JavaScript, strings are immutable. This means that once a string is created, it can't be changed. That might sound strange since in your code, it seems like you are changing the string finalName throughout the loop with methods like replace().
But in reality, you aren't actually changing it! The replace() function takes an input string, does the replacement, and produces a new output string, since it isn't actually allowed to change the input string (immutability). So, tl;dr, if you don't capture the output of replace() by assigning it to a variable, the replaced string is lost.
Incidentally, it's okay to assign it back to the original variable name, which is why you can do finalName = finalName.replace(...).
Replace is greedy
The other problem you'll run into is when you use replace(), you'll be replacing all of the matching characters in the string, not just the ones at the position you are examining. This is because replace() is greedy - if you tell it to replace 'e' with 'E', it'll replace all of them!
What you need to do, essentially, is:
Find a space character (you've already done this)
Grab all of the string up to and including the space; this "side" of the string is good.
Convert the very next letter to uppercase, but only that letter.
Grab the rest of the string, past the letter you converted.
Put all three pieces together (beginning of string, capitalized letter, end of string).
The slice() method will do what you want:
if (finalName.charAt(i) === " ") {
// Get ONLY the letter after the space
var startLetter = finalName.slice(i+1, i+2);
// Concatenate the string up to the letter + the letter uppercased + the rest of the string
finalName = finalName.slice(0, i+1) + startLetter.toUpperCase() + finalName.slice(i+2);
}
Another option is regular expression (regex), which the other answers mentioned. This is probably a better option, since it's a lot cleaner. But, if you're learning programming for the first time, it's easier to understand this manual string work by writing the raw loops. Later you can mess with the efficient way to do it.
Working jsfiddle: http://jsfiddle.net/9dLw1Lfx/
Further reading:
Are JavaScript strings immutable? Do I need a "string builder" in JavaScript?
slice() method
You can simplify this down a lot if you pass a RegExp /pattern/flags and a function into str.replace instead of using substrings
function nameChanger(oldName) {
var lowerCase = oldName.toLowerCase(),
titleCase = lowerCase.replace(/\b./g, function ($0) {return $0.toUpperCase()});
return titleCase;
};
In this example I've applied the change to any character . after a word boundary \b, but you may want the more specific /(^| )./g
Another good answer to this question is to use RegEx to do this for you.
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"
The regular expression being used may need to be changed up slightly, but this should give you an idea of what you can do with regular expressions
Capitalize Letters with JavaScript
The problem is twofold:
1) You need to return a value for finalName.replace, as the method returns an element but doesn't alter the one on which it's predicated.
2) You're not iterating through the string values, so you're only changing the first word. Don't you want to change every word so it's in lower case capitalized?
This code would serve you better:
var name = "AlbERt EINstEiN";
function nameChanger(oldName) {
// Your code goes here!
var finalName = [];
oldName.toLowerCase().split(" ").forEach(function(word) {
newWord = word.replace(word.charAt(0), word.charAt(0).toUpperCase());
finalName.push(newWord);
});
// Don't delete this line!
return finalName.join(" ");
};
// Did your code work? The line below will tell you!
console.log(nameChanger(name));
if (finalName.charAt(i) === " ")
Shouldn't it be
if (finalName.charAt(i) == " ")
Doesn't === check if the object types are equal which should not be since one it a char and the other a string.

JavaScript: How can I remove any words containing (or directly preceding) capital letters, numbers, or commas, from a string?

I'm trying to write the code so it removes the "bad" words from the string (the text).
The word is "bad" if it has comma or any special sign thereafter. The word is not "bad" if it contains only a to z (small letters).
So, the result I'm trying to achieve is:
<script>
String.prototype.azwords = function() {
return this.replace(/[^a-z]+/g, "0");
}
var res = "good Remove remove1 remove, ### rem0ve? RemoVE gooood remove.".azwords();//should be "good gooood"
//Remove has a capital letter
//remove1 has 1
//remove, has comma
//### has three #
//rem0ve? has 0 and ?
//RemoVE has R and V and E
//remove. has .
alert(res);//should alert "good gooood"
</script>
Try this:
return this.replace(/(^|\s+)[a-z]*[^a-z\s]\S*(?!\S)/g, "");
It tries to match a word (that is surrounded by whitespaces / string ends) and contains any (non-whitespace) character but at least one that is not a-z. However, this is quite complicated and unmaintainable. Maybe you should try a more functional approach:
return this.split(/\s+/).filter(function(word) {
return word && !/[^a-z]/.test(word);
}).join(" ");
okay, first off you probably want to use the word boundary escape \b in your regex. Also, it's a bit tricky if you match the bad words, because a bad word might contain lower case chars, so your current regex will exclude anything which does have lowecase letters.
I'd be tempted to pick out the good words and put them in a new string. It's a much easier regex.
/\b[a-z]+\b/g
NB: I'm not totally sure that it'll work for the first and last words in the string so you might need to account for that as well. http://www.regextester.com/ is exceptionally useful.
EDIT: as you want punctiation after the word to be 'bad', this will actually do what I was suggesting
(^|\s)[a-z]+(\s|$)
Firstly I wouldn't recommend changing the prototype of String (or of any native object) if you can avoid because you leave yourself open to conflicts with other code that might define the same property in different ways. Much better to put custom methods like this on a namespaced object, though I'm sure some will disagree.
Second, is there any need to use RegEx completely? (Genuine question; not trying to be facetious.)
Here is an example of the function with plain old JS using a little bit of RegEx here and there. Easier to comment, debug, and reuse.
Here is the code:
var azwords = function(str) {
var arr = str.split(/\s+/),
len = arr.length,
i = 0,
res = "";
for (i; i < len; i += 1) {
if (!(arr[i].match(/[^a-z]/))) {
res += (!res) ? arr[i] : " " + arr[i];
}
}
return res;
}
var res = "good Remove remove1 remove, ### rem0ve? RemoVE gooood remove."; //should be "good gooood"
//Remove has a capital letter
//remove1 has 1
//remove, has comma
//### has three #
//rem0ve? has 0 and ?
//RemoVE has R and V and E
//remove. has .
alert(azwords(res));//should alert "good gooood";
Try this one:
var res = "good Remove remove1 remove, ### rem0ve? RemoVE gooood remove.";
var new_one = res.replace(/\s*\w*[#A-Z0-9,.?\\xA1-\\xFF]\w*/g,'');
//Output `good gooood`
Description:
\s* # zero-or-more spaces
\w* # zero-or-more alphanumeric characters
[#A-Z0-9,.?\\xA1-\\xFF] # matches any list of characters
\w* # zero-or-more alphanumeric characters
/g - global (run over all string)
This will find all the words you want /^[a-z]+\s|\s[a-z]+$|\s[a-z]+\s/g so you could use match.
this.match(/^[a-z]+\s|\s[a-z]+$|\s[a-z]+\s/g).join(" "); should return the list of valid words.
Note that this took some time as a JSFiddle so it maybe more efficient to split and iterate your list.

In javascript, I'm having trouble figuring out how to make a regex replace only the capture and not the match

The following function is meant to remove random articles (parts of speech) from the text. Eventually the percentages will be user-adjustable, and the regex more sophisticated to catch word boundaries better, etc. It is replacing (and about 50/50), but it's also squashing the spaces (which are matched, but not captured). I think I'm being really bone-headed here but I can't figure out the proper syntax... can anyone help?
function posArticles(t) {
var text = t;
var re = / (a|the|an) /g;
var rArray;
text = text.replace(re, function(_, m) {
if (Math.floor(Math.random()*101) < 50) return '';
else return m;
});
return text;
}
I realize that this has to do with the positional/optional arguments to the anon function, but I can't figure out which is the match and which is the capture and so forth.
There are numerous ways you could do this, but I think your best bet is to use \b – a zero-width match for a "word boundary." That guarantees that you're getting "the" and not "there" or whatever, but doesn't match the spaces around it.
Thus, use re = /\b([Aa]n?|[Tt]he)\b/;
I realize that this has to do with the positional/optional arguments
to the anon function, but I can't figure out which is the match and
which is the capture and so forth.
First argument passed to your callback function is whole match (ie: _ = ' the '). Next argument are your captured groups (m = 'the'). Callback function is replacing whole match, so if you are including spaces in your expresion, they will also be replaced.
if (Math.floor(Math.random()*101) < 50) return ' ';
return a space instead of empty string :)

Regular Expression: Match Partial or full string

I have small script that takes the value from a text input and needs to match an item in an array either partially or fully.
I'm struggling at the moment with the regular expression and the syntax and wondered if I could pick your brains.
for (var i=0; i < liveFilterData.length; i+=1) {
if (liveFilterData[i].match(liveFilter.val())) {
alert();
}
}
I need the liveFilter.val() and Regular Expression to match the current array item liveFilterData[i] so if someone types in H or h in the text box, it checks if there is a matching item in the array. If they type in He or he then it matches Head, Header or heading.
Sorry, I've looked all over the web on how to build regular expressions but I can't work it out.
Simple string comparison shold do the trick:
for (var v, i = liveFilterData.length; i--;) {
if (liveFilterData[i].slice (0, (v = liveFilter.val().toLowerCase ()).length) === v) {
alert();
}
}
liveFilterData should contain the words in lower case.
I'm not sure I totally understand the question. Is liveFilter.val() a regular expression, or is it just a string that you are trying to match against any value in an array? I'm guessing that you have a event on the textbox's keypress, keydown or keypress, and that the code you wrote above runs in the callback to this event. If so, there are a number of things you can do to convert the value to an appropriate regex: "^"+liveFilter.val(), Since you are using the regex in a loop, you should precompile it with new RegExp, so your loop would look something like:
//the i in the second param here is a flag indicating case insensitive
//a hat '^' in regex means 'beginning of the input'
regex = new RegExp("^"+liveFilter.val(), i);
for (var i=0; i < liveFilterData.length; i+=1) {
// regex.test uses the precompiled regex, and determines if there is a match
if (regex.test(liveFilterData[i])) {
alert("matched " + i);
}
}
Hope this helps!

Categories