I'm not sure how to phrase this correctly. Basically, I want to take a string composed of a backslash an an "escapable" character and convert it to the actual escaped form:
console.log(magicStringFunction('\\n') === '\n') // true
What I'm trying to do is effectively the inverse of String.raw:
console.log(String.raw`\n` === '\\n') // true
I am aware that I can technically do this with eval:
console.log(eval('"\\n"')); // \n
However, I generally like to avoid using eval. Is there a way to do this with native code?
Found an answer! Just goes to show that I need to do a bit more investigating before asking a question...
You can use JSON.parse, which is similar to eval in this case, but less dangerous and (I believe) faster.
console.log(JSON.parse('"\\n"') === '\n') // true
This is one of your proposed solution:
function magicStringFunction(w){
return JSON.parse('"' + w + '"');
}
But it will fail when this happens:
magicStringFunction('"\\n"'); // whoops
A version that prevents this from happening:
function magicStringFunction(w){
return w.replace(/\\./g, function(match){
return JSON.parse('"' + match + '"');
});
}
Might not be exactly very efficient but it works.
Or if you are not a big fan of JSON.parse for efficiency, you can do this instead:
function magicStringFunction(w){
// Defined by Table 34 under section 11.8.4.3
// ' " \ b f n r t v
var escCharMap = {
"\\'": "'",
"\\\"": "\"",
"\\\\": "\\",
"\\b": "\b",
"\\f": "\f",
"\\n": "\n",
"\\r": "\r",
"\\t": "\t",
"\\v": "\v"
};
return w.replace(/\\./g, function(match){
if(escCharMap.hasOwnProperty(match)) return escCharMap[match];
else return match.substr(1, 1);
});
}
Ref: http://www.ecma-international.org/ecma-262/7.0/index.html#prod-SingleEscapeCharacter
Related
I have a string like the following:
"[a,b,c],[d,e,f],[g,h,i]"
I was wondering how can I separate the string by ],[ in JavaScript. .split("],[") will remove the brackets. I want to preserve them.
Expected output:
["[a,b,c]","[d,e,f]","[g,h,i]"]
Edit:
Here is a more complicated case that I highlighted in a comment on #Leo's answer (wherein a ],[-delimited string contains ],):
"[dfs[dfs],dfs],[dfs,df,sdfs]]"
Expected output:
["[dfs[dfs],dfs]","[dfs,df,sdfs]]"]
Try this:
"[a,b,c],[d,e,f],[g,h,i]".match(/(\[[^\]]+\])/g)
// ["[a,b,c]", "[d,e,f]", "[g,h,i]"]
EDIT For OP's new case, here's the trick:
"[dfs[dfs],dfs],[dfs,df,sdfs]]".match(/(?!,\[).+?\](?=,\[|$)/g)
// ["[dfs[dfs],dfs]", "[dfs,df,sdfs]]"]
It works for even more complicated cases:
"[dfs[aa,[a],dfs],[dfs[dfs],dfs],[dfs,df,sdfs]]".match(/(?!,\[).+?\](?=,\[|$)/g)
// ["[dfs[aa,[a],dfs]", "[dfs[dfs],dfs]", "[dfs,df,sdfs]]"]
"[dfs[aa,[a],dfs],[dfs[dfs],dfs],[dfs,df,sdfs]],[dfs,df,sdfs]]".match(/(?!,\[).+?\](?=,\[|$)/g)
// ["[dfs[aa,[a],dfs]", "[dfs[dfs],dfs]", "[dfs,df,sdfs]]", "[dfs,df,sdfs]]"]
Below is my personal opinion
However, JavaScript's RegExp doesn't support lookbehind (?<, which is super handy for such requirements), using RegExp may become a maintainability nightmare. In this situation, I'd suggest an approach like, maybe #alienchow's replacing delimiters - not so neat, but more maintainable.
Personally I'd do
"[dfs[dfs],dfs],[dfs,df,sdfs]]".split("],[");
then loop through it to:
Append the first string with a "]".
Prepend the last string with a "[".
Prepend a "[" and append a "]" to all strings in between.
However, if you know what kind of strings and characters you will be receiving and you reaaaaally want a one-liner approach, you could try the hack below.
Replace all instances of "],[" with "]unlikely_string_or_special_unicode[", then split by "unlikely_string_or_special_unicode" - for example:
"[dfs[dfs],dfs],[dfs,df,sdfs]]".replace(/\],\[/g,"]~I_have_a_dream~[").split("~I_have_a_dream~");
Warning: Not 100% full-proof. If your input string has the unlikely string you used as a delimiter, then it implodes and the universe comes to an end.
TMTOWDI
I prefer doing this with a regex as #Leo explained, but another way to do it in the spirit of TMTOWDI & completeness is with the map function following the split:
var test = "[a,b,c],[d,e,f],[g,h,i]";
var splitTest = test.split("],[").map(
function(str) {
if (str[0] !== '[') {
str = '[' + str;
}
if (str[str.length - 1] !== ']') {
str += ']';
}
return str;
});
// FORNOW: to see the results
for (var i = 0; i < splitTest.length; i++) {
alert(splitTest[i]);
}
Afterthought:
If you perchance have an empty pair of square brackets in your ],[-delimited string (i.e. "[a,b,c],[d,e,f],[],[g,h,i]" for example), this approach will preserve it too (as would changing #Leo's regex from /(\[[^\]]+\])/g to /(\[[^\]]*\])/g).
TMTOWDI Redeux
With the curveball that ] and [ may be within the ],[-delimited strings (per your comment on #Leo's answer), here is a rehash of my initial approach that is more robust:
var test = "[dfs[dfs],dfs],[dfs,df,sdfs]]";
var splitTest = test.split("],[").map(
function(str, arrIndex, arr) {
if (arrIndex !== 0) {
str = '[' + str;
}
if (arrIndex !== arr.length - 1) {
str += ']';
}
return str;
});
// FORNOW: to see the results
for (var i = 0; i < splitTest.length; i++) {
alert(splitTest[i]);
}
Python's strip function is used to remove given characters from the beginning and end of the string. How to create a similar function in javascript?
Example:
str = "'^$ *# smart kitty & ''^$* '^";
newStr = str.strip(" '^$*#&");
console.log(newStr);
Output:
smart kitty
There's lodash's trim()
Removes leading and trailing whitespace or specified characters from string.
_.trim(' abc '); // → 'abc'
_.trim('-_-abc-_-', '_-'); // → 'abc'
A simple but not very effective way would be to look for the characters and remove them:
function strip(str, remove) {
while (str.length > 0 && remove.indexOf(str.charAt(0)) != -1) {
str = str.substr(1);
}
while (str.length > 0 && remove.indexOf(str.charAt(str.length - 1)) != -1) {
str = str.substr(0, str.length - 1);
}
return str;
}
A more effective, but not as easy to use, would be a regular expression:
str = str.replace(/(^[ '\^\$\*#&]+)|([ '\^\$\*#&]+$)/g, '')
Note: I escaped all characters that have any special meaning in a regular expression. You need to do that for some characters, but perhaps not all the ones that I escaped here as they are used inside a set. That's mostly to point out that some characters do need escaping.
Modifying a code snippet from Mozilla Developer Network String.prototype.trim(), you could define such a function as follows.
if (!String.prototype.strip) {
String.prototype.strip = function (string) {
var escaped = string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
return this.replace(RegExp("^[" + escaped + "]+|[" + escaped + "]+$", "gm"), '');
};
}
It's not necessary and probably not advisable to put this function in the object String.prototype, but it does give you a clear indication of how such a function compares with the existing String.prototype.trim().
The value of escaped is as in the function escapeRegExp in the guide to Regular Expressions. The Java programming language has a standard library function for that purpose, but JavaScript does not.
Not exactly... I would use regex for complicated string manipulation or the Slice() method to remove characters at certain points
Slice() explained
Just when you think you've got a handle on regex; it all comes undone. Hoping to return a false check if anything other than alpha numeric and whitespace characters are found.
function checkName(fname)
{
var rexp = new RegExp(/[^a-zA-Z0-9]\s/gim)
if (!rexp.test(fname))
{
alert ("'" + fname + "'\nis okay")
}
else
{
alert ("'" + fname + "'\nis NOT okay")
}
return !rexp.test(fname)
}
I would hope that the above code would return for the following
"This is ok" - true
"This, is not ok" -false
"Nor is this ok!" -false
"Nor is \"this ok" - false
Although much of the discussion is right, everything seems to be missing the point that you are inverting character classes and then inverting the results in your function. This is logically hard to read. You also do two tests on the regex for no good reason. Much cleaner would be something like this:
function checkName(fname) {
var result = /^[a-z0-9\s]+$/i.test(fname)
if (result) {
alert ("'" + fname + "'\nis okay")
} else {
alert ("'" + fname + "'\nis NOT okay")
}
return result;
}
Update: It looks like Jack's edits captured these points too. (Always a minute late and a nickel short...)
[^a-zA-Z0-9]\s
Your regex requires the whitespace to be after the letters/numbers.
To fix it, move the \s inside the brackets.
You still have to do one more thing though. The regex will only match one of these characters. Add a + to match one or more.
Therefore, fixed regex:
[^a-zA-Z0-9\s]+
A few things:
/something/ is the short notation for new RegExp('something'); you shouldn't mix them up.
You need to move the \s inside the character class; otherwise you match a character that's not alphanumeric followed by a space.
I don't think you need all those modifiers:
/m is only useful if you have anchors in your expression,
/i can be used if you remove A-Z or a-z from the character class,
/g is only useful for when you need to match multiple times, but in your case the first match is enough.
var rexp = /[^a-zA-Z0-9\s]/;
The whole function can be written like this:
function checkName(fname)
{
return !/[^a-zA-Z0-9\s]/.test(fname);
}
Instead of using double negatives, it would be better to say "only allow these characters":
function checkName(fname)
{
return /^[a-zA-Z0-9\s]*$/.test(fname);
}
If you need to test for non-empty names as well, you should use /^[a-zA-Z0-9\s]+$/.
Try:
function checkName(fname)
{
var rexp = new RegExp(/^[a-z0-9\s]+$/i)
if (!rexp.test(fname))
{
alert ("'" + fname + "'\nis okay")
}
else
{
alert ("'" + fname + "'\nis NOT okay")
}
return !rexp.test(fname)
}
I've been getting better at Regex, but I've come up with something that is beyond what I'm currently able to do.
I want to build a function to test (return true or false) to test to see if a word is found inside a string. But I wouldn't want to have a positive match if the word was found inside of another word. I would also like to build in the possibility of checking for pluralization.
Here are some examples of the results I'd expect to get:
Word to look for: "bar"
"Strings to search in" //what it should return as
"foo bar" //true
"foo bar." //true
"foo bar!" //true (would be true with any other punctuation before or after 'bar' too)
"foo bars." //true
"foo bares." //true (even though bares has a different meaning then bars, I would be okay with this returning true since I would need to check for words that pluralize with "es" and I wouldn't expect to build a regex to know which words pluralize with "s" and which to "es")
"my name is bart simpson" //false (bar is actually part of "bart")
"bart simpson went to the bar." //true
I'll be using javascript/jquery to check for matches
Thanks so much for the help!
var rgx = new RegExp('\\b' + word + '(?:es|s)?\\b');
rgx.test(string);
This will return true for all of the strings you specified in your request. \b represents a "word boundary," which I believe is any character in \W (including period and exclamation point) as well as the start or end of the string.
This has already been answered and accepted, but I thought I'd provide a slightly over-engineered approach that does a better job of matching plural forms. Other than that, it uses exactly the same logic as #ExplosionPills' solution:
(function() {
var isWord = function(word) { return /^[a-z]+$/i.test(word); },
exceptions = {
man: 'men',
woman: 'women',
child: 'children',
mouse: 'mice',
tooth: 'teeth',
goose: 'geese',
foot: 'feet',
ox: 'oxen'
},
pluralise = function(word) {
word = word.toLowerCase();
if (word in exceptions) {
// Exceptions
return '(?:' + word + '|' + exceptions[word] + ')';
} else if (word.match(/(?:x|s|[cs]h)$/)) {
// Sibilants
return word + '(?:es)?';
} else if (word.match(/[^f]f$/)) {
// Non-Geminate Labio-Dental Fricative (-f > -ves / -fs)
return '(?:' + word + 's?|' + word.replace(/f$/, 'ves') + ')';
} else if (word.match(/[^aeiou]y$/)) {
// Close-Front Unround Pure Vowel (-Cy > -Cies)
return '(?:' + word + '|' + word.replace(/y$/, 'ies') + ')';
} else if (word.substr(-1) == 'o') {
// Mid-Back Round Vowel (-o > -oes / -os)
return word + '(?:e?s)?';
} else {
// Otherwise
return word + 's?';
}
};
String.prototype.containsNoun = function(singularNoun) {
if (!isWord(singularNoun)) throw new TypeError('Invalid word');
var check = new RegExp('\\b' + pluralise(singularNoun) + '\\b', 'gi');
return check.test(this);
};
String.prototype.pluralException = function(plural) {
if (!isWord(this) || !isWord(plural)) throw new TypeError('Invalid exception');
var singular = this.toLowerCase();
plural = plural.toLowerCase();
if (!(singular in exceptions)) {
exceptions[singular] = plural;
}
};
})();
It extends the native String object, so you use it like so:
'Are there some foos in here?'.containsNoun('foo'); // True
See the gist for some quick-and-dirty unit testing done in Node.js.
/ (bar((e)?s)?)[ !?.]/
depending on what you need exactly this might work.
it won't find two bars in the string "bars bars" because of the overlapping spaces.
/ (bar((e)?s)?)(?=[ !?.])/
that should work with "bars bars" (two matches) since js1.5 which is supported by all the browsers anyway nowadays.
A string length which contains one space is always equal to 1:
alert('My str length: ' + str.length);
The space is a character, so:
str = " ";
alert('My str length:' + str.length); // My str length: 3
How can I make a distinction between an empty string and a string which contains only spaces? How can I detect a string which contain only spaces?
To achieve this you can use a Regular Expression to remove all the whitespace in the string. If the length of the resulting string is 0, then you can be sure the original only contained whitespace. Try this:
var str = " ";
if (!str.replace(/\s/g, '').length) {
console.log('string only contains whitespace (ie. spaces, tabs or line breaks)');
}
The fastest solution would be using the regex prototype function test() and looking for any character that is not a space, tab, or line break \S :
if (!/\S/.test(str)) {
// Didn't find something other than a space which means it's empty
}
In case you have a super long string, it can make a significant difference as it will stop processing as soon as it finds a non-space character.
Similar to Rory's answer, with ECMA 5 you can now just call str.trim().length instead of using a regular expression. If the resulting value is 0 you know you have a string that contains only spaces.
if (!str.trim().length) {
console.log('str is empty!');
}
You can read more about trim here.
Edit: After looking at this a few years later I noticed this could be simplified further. Since the result of trim will either be truthy or falsy you can also do the following:
if (!str.trim()) {
console.log('str is empty!');
}
if(!str.trim()){
console.log('string is empty or only contains spaces');
}
String#trim() removes the whitespace at the start and end of the string. If the string contained only whitespace, it would be empty after trimming, and the empty string is falsey in JavaScript.
If the string might be null or undefined, we need to first check if the string itself is falsey before trimming.
if(!str || !str.trim()){
//str is null, undefined, or contains only spaces
}
This can be simplified using the optional chaining operator.
if(!str?.trim()){
//str is null, undefined, or contains only spaces
}
You can Trim your String value by creating a trim function for your Strings.
String.prototype.trim = function () {
return this.replace(/^\s*/, "").replace(/\s*$/, "");
}
now it will be available for your every String and you can use it as
str.trim().length// Result will be 0
You can also use this method to remove the white spaces at the start and end of the String i.e
" hello ".trim(); // Result will be "hello"
You can do this by simply using trim.
var str = " ";
if (str.trim().length == 0)
{
console.log("Your string contains only white spaces.")
}
Trim your String value by creating a trim function
var text = " ";
if($.trim(text.length == 0){
console.log("Text is empty");
}
else
{
console.log("Text is not empty");
}
If we want to check if string contains only white spaces, then this might be helpful.
const str = ' ';
console.log(/^\s+$/.test(str));
This will log true.
Typecasting to Number can detect whitespace-only strings (if strings containing only zeros can be excluded):
if (+' ' === 0) console.log('is whitespace');
to make this approach also work for empty- and zerostrings like '0' a truthy numerical prefix could be used:
if (Number('1 0') === 1) console.log('is not whitespace');
if (Number('1 ' + ' \n ') === 1) console.log('is whitespace');
but concatenated casting is expensive - leading to this obscure expression:
String(x || '').indexOf('0') < +x
however, performance- and readability wise - trimed-length still wins over regex or casting-magic.
const tests = ['',' ', '\t\n\r','0',' 0 ','x',' 404 '];
tests.filter(x => String(x || '').trim().length === 0); // fastest
tests.filter(x => /^\s*$/.test(x)); // 33% slower
tests.filter(x => +x === 0 && String(x).indexOf('0') === -1); // 40 % slower
tests.filter(x => String(x || '').indexOf('0') < +x); // 50% slower
tests.filter(x => Number('1 ' + x) === 1); // 66% slower
This works in Dart not Javascript. However, when I searched up how to do this with Dart this question came up, so I figured others may need the Dart answer.
String foo = ' ';
if (foo.replaceAll(' ', '').length == 0) {
print('ALL WHITE SPACE');
}
else {
print('NOT ALL WHITE SPACE');
}
To further clarify, the String ' d ' will print 'NOT ALL WHITE SPACE' and the String ' ' will print 'ALL WHITE SPACE'.