Cross browser Javascript regex - javascript

I am using the following code to convert a dynamic string into a valid class.
domain.replace('.','_','gi')
This works fine in all major browsers, but not in Internet Explorer and I'm wondering why. The gi flags are for global and case insensitive, but removing them means that the replace doesn't work in Firefox either.
Any ideas on how I change this to make it more friendly with more browers?

You'll need to use an actual regexp instead of a string:
domain.replace(/\./g, "_")
The third argument (flags) is non-standard.

You need to do it like this:
domain.replace(/\./g, '_');

Related

Is there a more rational way to replace all slashes using javascript than this?

var input = '/string/';
var output = input.replace(/\//g,'');
// requested output = 'string';
What I don't like about this method is that the double slashes might be considered a comment and ignored by certain browsers, or am I wrong?
It works in my browser, but I can't test in every browser. Is it a perfectly proper method, or is there a better solution?
What I don't like about this method is that the double slashes might be considered a comment and ignored by certain browsers
What double slashes? The ones in the regexp? Certainly not, unless the browser's JavaScript parser is totally broken.
Is it a perfectly proper method
Yes.
That is the correct way to do the replacement. The double slashes won't be interpreted as a comment by any production browser; that regex form is a valid part of EMCAScript.
It should be alright but if you're really concerned, use a RegExp object, eg
var re = new RegExp("/", "g");
var output = input.replace(re, '');
Yes, the syntax is correct. It will work with any JavaScript engine.

Case insensitive XPath contains() possible?

I'm running over all textnodes of my DOM and check if the nodeValue contains a certain string.
/html/body//text()[contains(.,'test')]
This is case sensitive. However, I also want to catch Test, TEST or TesT. Is that possible with XPath (in JavaScript)?
This is for XPath 1.0. If your environment supports XPath 2.0, see here.
Yes. Possible, but not beautiful.
/html/body//text()[
contains(
translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
'test'
)
]
This would work for search strings where the alphabet is known beforehand. Add any accented characters you expect to see.
If you can, mark the text that interests you with some other means, like enclosing it in a <span> that has a certain class while building the HTML. Such things are much easier to locate with XPath than substrings in the element text.
If that's not an option, you can let JavaScript (or any other host language that you are using to execute XPath) help you with building an dynamic XPath expression:
function xpathPrepare(xpath, searchString) {
return xpath.replace("$u", searchString.toUpperCase())
.replace("$l", searchString.toLowerCase())
.replace("$s", searchString.toLowerCase());
}
xp = xpathPrepare("//text()[contains(translate(., '$u', '$l'), '$s')]", "Test");
// -> "//text()[contains(translate(., 'TEST', 'test'), 'test')]"
(Hat tip to #KirillPolishchuk's answer - of course you only need to translate those characters you're actually searching for.)
This approach would work for any search string whatsoever, without requiring prior knowledge of the alphabet, which is a big plus.
Both of the methods above fail when search strings can contain single quotes, in which case things get more complicated.
XPath 2.0 Solutions
Use lower-case():
/html/body//text()[contains(lower-case(.),'test')]
Use matches() regex matching with its case-insensitive
flag:
/html/body//text()[matches(.,'test', 'i')]
Case-insensitive contains
/html/body//text()[contains(translate(., 'EST', 'est'), 'test')]
Yes. You can use translate to convert the text you want to match to lower case as follows:
/html/body//text()[contains(translate(.,
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'),
'test')]
The way i always did this was by using the "translate" function in XPath. I won't say its very pretty but it works correctly.
/html/body//text()[contains(translate(.,'abcdefghijklmnopqrstuvwxyz',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'),'TEST')]
hope this helps,
If you're using XPath 2.0 then you can specify a collation as the third argument to contains(). However, collation URIs are not standardized so the details depend on the product that you are using.
Note that the solutions given earlier using translate() all assume that you are only using the 26-letter English alphabet.
UPDATE: XPath 3.1 defines a standard collation URI for case-blind matching.

javascript/jQuery can't find element with messed up id

I'm trying to access an element in MS CRM 2011 with the following id:
account|NoRelationship|Form|B_GenerateInvoice-Large
I can see this element in the IE developer tools:
Unfortunately I always get null when trying to find this element.
I've tried the following:
alert(document.getElementById('account|NoRelationship|Form|B_GenerateInvoice-Large'));
alert($("[id='account|NoRelationship|Form|B_GenerateInvoice-Large]").html());
alert($(jq("account|NoRelationship|Form|B_GenerateInvoice-Large")).html()); // jq() adds the '#' and escapes special characters
alert($("#account|NoRelationship|Form|B_GenerateInvoice-Large").html());
alert(document.getElementById("#account\\|NoRelationship\\|Form\\|B_GenerateInvoice-Large"));
alert($("#account\\|NoRelationship\\|Form\\|B_GenerateInvoice-Large").html());
These all fail to find the element.
Am I missing something obvious here?
Solution:
The javascript was inside an iframe while the element was outside of the iframe..
I did not manage to solve it.
The jQuery Manual on Selectors states:
If you wish to use any of the
meta-characters ( such as
!"#$%&'()*+,./:;<=>?#[]^`{|}~ ) as a
literal part of a name, you must
escape the character with two
backslashes: \\. For example, if you
have an element with id="foo.bar", you
can use the selector $("#foo\\.bar").
The W3C CSS specification contains the
complete set of rules regarding valid CSS selectors.
So try this one:
$('#account\\|NoRelationship\\|Form\\|B_GenerateInvoice-Large')...
jsFiddle Demo
EDIT: I have successfully tested my Fiddle in Chrome, Firefox 4, IE9, IE8 and IE7, it works fine.
It may be a bug in browser, since HTML5 specification allows any character except spaces in id attribute
ID #
Any string, with the following restrictions:
must be at least one character long
must not contain any space characters
however, it is encrouaged not to put any weired character in id attribute, only number, letter and underscore there:)
From the jQuery documentation:
If you wish to use any of the meta-characters ( such as !"#$%&'()*+,./:;<=>?#[]^`{|}~ ) as a literal part of a name, you must escape the character with two backslashes: \. For example, if you have an element with id="foo.bar", you can use the selector $("#foo\.bar").
So this should work:
alert($("#account\\|NoRelationship\\|Form\\|B_GenerateInvoice-Large").html());
And it does, indeed: http://jsfiddle.net/Cdz9w/
What version of HTML is the page declaring that it's using? Because that's a valid HTML5 id, but it's an invalid HTML4.01 and earlier id. (It's also an invalid CSS id, which is vaguely relevant if you use something like jQuery to look it up, as jQuery uses CSS selectors.)
The fiddle in #bazmegakapa's answer works for me on Chrome, but perhaps your page is declaring a different version of HTML, or perhaps a less-advanced browser doesn't like it, etc.

Why doesn't the javascript replace global flag work in Chrome or IE, and how to I work around it?

According to the String.prototype.replace() page on MDN, I should be able to easily replace multiple patterns just by using
str.replace('what to replace', 'replace with', 'flags')
and setting the flags to 'g'.
It works perfect in Firefox 3.6. But in Chrome and IE8, it only replaces the first 'what to replace'.
I can use the
str.replace(/what to replace/gi, 'replace with')
syntax. But I'm pulling the 'what to replace' out of an array, which makes it hard to add the flags in that syntax.
Here's the code I'm trying to use. How to I modify it to work in Chrome as well as Firefox?
function generateQuestion()
{
//alert('variable length: '+variableList.length);
for(i=0;i<variableList.length;i++)
{
variable = variableList[i];
rep = replacementList[i];
flags = "gi";
questionText = questionText.replace(variable, rep, flags);
}
}
And why do I have to bother modifying it at all? Shouldn't Chrome evaluate the JavaScript as described in the link?
The very page you linked to mentions:
The use of the flags parameter in the String.replace method is non-standard. For cross-browser compatibility, use a RegExp object with corresponding flags.
Basically, it should only work on Firefox. As per the documentation, you can generate regexes dynamically using new RegExp:
var regex = new RegExp(variable, 'gi');
questionText = questionText.replace(regex, rep);
This will need variable to be escaped, however.
It appears that webkit's implementation of string.replace perhaps doesn't have the 3rd parameter, as 'foo'.replace('o','i','g') results in fio for me.
The following appears to work however:
'foo'.replace(/o/gi,'i')
Another option is:
'foo'.replace(new RegExp('o', 'gi'),'i')
From Mozilla Developer Network - JavaScript - String - replace
Non-standard
The use of the flags parameter in the String.replace method is non-standard. For cross-browser compatibility, use a RegExp object with corresponding flags.
Working in Chrome and Firefox
To get your code to work in Chrome and Firefox, you'll have to create a RegExp object (since your strings aren't hardcoded) with the appropriate flags. See Mozilla Developer Network - RegExp

IE8 window.open name - doesn't like JavaScript encoding?

I'm calling window.open() like this:
window.open('blank.html', 'New_Window\x3a_Jamie', 'width=800,height=800');
What I've done in the code is taken the window's name and JavaScript encoded it using the Microsoft Web Protection library. I'm also replacing spaces with underscores because I read that IE doesn't like spaces in window names. FYI the original string was "New Window: Jamie" and it looks like the ":" gets encoded as "\x3a". The window opens in FireFox just fine, but the window does not open in IE8. Does IE8 just not like this encoding, or the character or what? Are there rules around what characters can appear in the window name for IE8?
Are there rules around what characters can appear in the window name for IE8?
Yes. Although it doesn't seem to be documented, IE has always required that a window name be composed of alphanumerics and underscore. A colon won't be accepted, whether read from an encoded string literal or not.
If you really needed to map an arbitrary string to a unique name-safe version you'd have to do something like encoding every non-alphanumeric character into an escape sequence, eg:
function encodeToName(s) {
return s.replace(/[^A-Za-z0-9]/g, function(match) {
var c= match[0].charCodeAt(0).toString(16);
return '_'+(new Array(5-c.length).join('0'))+c;
});
}
alert(encodeToName('New Window: Jamie'));
// 'New_0020Window_003A_0020Jamie'
I agree with casablanca though, it seems very unlikely you should actually need to do this. The user is never going to get to see the window name, so w1 is just as good. It's rare enough that you need window names at all.
I think it wants the window name to be something that'd work as an identifier. Thus, "New_Window_Jamie" would probably be OK.
Do you really need a window name? From the docs:
Such string can be used to be the target of links and forms when the target attribute of an <a> element or of a <form> is specified. This string parameter should not contain any blank space.
That's about the only use of specifying a name, and though I don't see any restrictions apart from "no spaces", it would be safe to just stick to letters, digits and underscores.

Categories

Resources