在JavaScript中是否有一种方法来检查字符串是否是URL?

regex被排除在外,因为URL很可能写成stackoverflow;也就是说,它可能没有。com, WWW或http。


当前回答

这显然不是最有效的方法,但它是可读的,并且很容易形成您需要的任何形式。从这里添加regex/complexity更容易。这是一个非常实用的方法

const validFirstBits = ["ftp://", "http://", "https://", "www."];
const invalidPatterns = [" ", "//.", ".."];

export function isUrl(word) {
// less than www.1.dk
if (!word || word.length < 8) return false;

// Let's check and see, if our candidate starts with some of our valid first bits
const firstBitIsValid = validFirstBits.some(bit => word.indexOf(bit) === 0);
if (!firstBitIsValid) return false;

const hasInvalidPatterns = invalidPatterns.some(
    pattern => word.indexOf(pattern) !== -1,
);

if (hasInvalidPatterns) return false;

const dotSplit = word.split(".");
if (dotSplit.length > 1) {
    const lastBit = dotSplit.pop(); // string or undefined
    if (!lastBit) return false;
    const length = lastBit.length;
    const lastBitIsValid =
        length > 1 || (length === 1 && !isNaN(parseInt(lastBit)));
    return !!lastBitIsValid;
}

    return false;
}

测试:

import { isUrl } from "./foo";

describe("Foo", () => {
    test("should validate correct urls correctly", function() {
        const validUrls = [
            "http://example.com",
            "http://example.com/blah",
            "http://127.0.0.1",
            "http://127.0.0.1/wow",
            "https://example.com",
            "https://example.com/blah",
            "https://127.0.0.1:1234",
            "ftp://example.com",
            "ftp://example.com/blah",
            "ftp://127.0.0.1",
            "www.example.com",
            "www.example.com/blah",
        ];

        validUrls.forEach(url => {
            expect(isUrl(url) && url).toEqual(url);
        });
    });

    test("should validate invalid urls correctly", function() {
        const inValidUrls = [
            "http:// foo.com",
            "http:/foo.com",
            "http://.foo.com",
            "http://foo..com",
            "http://.com",
            "http://foo",
            "http://foo.c",
        ];

        inValidUrls.forEach(url => {
            expect(!isUrl(url) && url).toEqual(url);
        });
    });
});

其他回答

我使用下面的函数来验证URL是否有http/https:

function isValidURL(string) { var res = string.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g); return (res !== null) }; var testCase1 = "http://en.wikipedia.org/wiki/Procter_&_Gamble"; console.log(isValidURL(testCase1)); // return true var testCase2 = "http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707"; console.log(isValidURL(testCase2)); // return true var testCase3 = "https://sdfasd"; console.log(isValidURL(testCase3)); // return false var testCase4 = "dfdsfdsfdfdsfsdfs"; console.log(isValidURL(testCase4)); // return false var testCase5 = "magnet:?xt=urn:btih:123"; console.log(isValidURL(testCase5)); // return false var testCase6 = "https://stackoverflow.com/"; console.log(isValidURL(testCase6)); // return true var testCase7 = "https://w"; console.log(isValidURL(testCase7)); // return false var testCase8 = "https://sdfasdp.ppppppppppp"; console.log(isValidURL(testCase8)); // return false

这里只是一个非常简单的检查,以确保有一个有效的协议,并且域扩展名必须是两个或更多字符。

is_valid_url = ( $url ) => {

    let $url_object = null;

    try {
        $url_object = new URL( $url );
    } catch ( $error ) {
        return false;
    }

    const $protocol = $url_object.protocol;
    const $protocol_position = $url.lastIndexOf( $protocol );
    const $domain_extension_position = $url.lastIndexOf( '.' );

    return (
        $protocol_position === 0 &&
        [ 'http:', 'https:' ].indexOf( $protocol ) !== - 1 &&
        $domain_extension_position > 2 && $url.length - $domain_extension_position > 2
    );

};

As has been noted the perfect regex is elusive but still seems to be a reasonable approach (alternatives are server side tests or the new experimental URL API). However the high ranking answers are often returning false for common URLs but even worse will freeze your app/page for minutes on even as simple a string as isURL('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'). It's been pointed out in some of the comments, but most probably haven't entered a bad value to see it. Hanging like that makes that code unusable in any serious application. I think it's due to the repeated case insensitive sets in code like ((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|' .... Take out the 'i' and it doesn't hang but will of course not work as desired. But even with the ignore case flag those tests reject high unicode values that are allowed.

已经提到的最好的是:

function isURL(str) {
  return /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(str); 
}

That comes from Github segmentio/is-url. The good thing about a code repository is you can see the testing and any issues and also the test strings run through it. There's a branch that would allow strings missing protocol like google.com, though you're probably making too many assumptions then. The repository has been updated and I'm not planning on trying to keep up a mirror here. It's been broken up into separate tests to avoid RegEx redos which can be exploited for DOS attacks (I don't think you have to worry about that with client side js, but you do have to worry about your page hanging for so long that your visitor leaves your site).

在dperini/regex- webburl .js中,我还看到过另一个存储库,它可能更适合isURL,但它非常复杂。它有一个更大的有效和无效url的测试列表。上面的简单的一个仍然通过了所有的正面信息,只有一些奇怪的负面信息,如http://a.b--c.de/以及特殊的ip。

无论你选择哪一个,在使用浏览器的开发人员工具检查器时,通过这个函数运行它,这个函数是我从dperini/regex- webburl .js上的测试中改编的。

function testIsURL() {
//should match
console.assert(isURL("http://foo.com/blah_blah"));
console.assert(isURL("http://foo.com/blah_blah/"));
console.assert(isURL("http://foo.com/blah_blah_(wikipedia)"));
console.assert(isURL("http://foo.com/blah_blah_(wikipedia)_(again)"));
console.assert(isURL("http://www.example.com/wpstyle/?p=364"));
console.assert(isURL("https://www.example.com/foo/?bar=baz&inga=42&quux"));
console.assert(isURL("http://✪df.ws/123"));
console.assert(isURL("http://userid:password@example.com:8080"));
console.assert(isURL("http://userid:password@example.com:8080/"));
console.assert(isURL("http://userid@example.com"));
console.assert(isURL("http://userid@example.com/"));
console.assert(isURL("http://userid@example.com:8080"));
console.assert(isURL("http://userid@example.com:8080/"));
console.assert(isURL("http://userid:password@example.com"));
console.assert(isURL("http://userid:password@example.com/"));
console.assert(isURL("http://142.42.1.1/"));
console.assert(isURL("http://142.42.1.1:8080/"));
console.assert(isURL("http://➡.ws/䨹"));
console.assert(isURL("http://⌘.ws"));
console.assert(isURL("http://⌘.ws/"));
console.assert(isURL("http://foo.com/blah_(wikipedia)#cite-1"));
console.assert(isURL("http://foo.com/blah_(wikipedia)_blah#cite-1"));
console.assert(isURL("http://foo.com/unicode_(✪)_in_parens"));
console.assert(isURL("http://foo.com/(something)?after=parens"));
console.assert(isURL("http://☺.damowmow.com/"));
console.assert(isURL("http://code.google.com/events/#&product=browser"));
console.assert(isURL("http://j.mp"));
console.assert(isURL("ftp://foo.bar/baz"));
console.assert(isURL("http://foo.bar/?q=Test%20URL-encoded%20stuff"));
console.assert(isURL("http://مثال.إختبار"));
console.assert(isURL("http://例子.测试"));
console.assert(isURL("http://उदाहरण.परीक्षा"));
console.assert(isURL("http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com"));
console.assert(isURL("http://1337.net"));
console.assert(isURL("http://a.b-c.de"));
console.assert(isURL("http://223.255.255.254"));
console.assert(isURL("postgres://u:p@example.com:5702/db"));
console.assert(isURL("https://d1f4470da51b49289906b3d6cbd65074@app.getsentry.com/13176"));

//SHOULD NOT MATCH:
console.assert(!isURL("http://"));
console.assert(!isURL("http://."));
console.assert(!isURL("http://.."));
console.assert(!isURL("http://../"));
console.assert(!isURL("http://?"));
console.assert(!isURL("http://??"));
console.assert(!isURL("http://??/"));
console.assert(!isURL("http://#"));
console.assert(!isURL("http://##"));
console.assert(!isURL("http://##/"));
console.assert(!isURL("http://foo.bar?q=Spaces should be encoded"));
console.assert(!isURL("//"));
console.assert(!isURL("//a"));
console.assert(!isURL("///a"));
console.assert(!isURL("///"));
console.assert(!isURL("http:///a"));
console.assert(!isURL("foo.com"));
console.assert(!isURL("rdar://1234"));
console.assert(!isURL("h://test"));
console.assert(!isURL("http:// shouldfail.com"));
console.assert(!isURL(":// should fail"));
console.assert(!isURL("http://foo.bar/foo(bar)baz quux"));
console.assert(!isURL("ftps://foo.bar/"));
console.assert(!isURL("http://-error-.invalid/"));
console.assert(!isURL("http://a.b--c.de/"));
console.assert(!isURL("http://-a.b.co"));
console.assert(!isURL("http://a.b-.co"));
console.assert(!isURL("http://0.0.0.0"));
console.assert(!isURL("http://10.1.1.0"));
console.assert(!isURL("http://10.1.1.255"));
console.assert(!isURL("http://224.1.1.1"));
console.assert(!isURL("http://1.1.1.1.1"));
console.assert(!isURL("http://123.123.123"));
console.assert(!isURL("http://3628126748"));
console.assert(!isURL("http://.www.foo.bar/"));
console.assert(!isURL("http://www.foo.bar./"));
console.assert(!isURL("http://.www.foo.bar./"));
console.assert(!isURL("http://10.1.1.1"));}

然后测试这串a。

在你发布一个看起来很棒的正则表达式之前,看看Mathias Bynens对isURL正则表达式的比较,了解更多信息。

一个有答案的相关问题

或者来自Devshed的Regexp:

function validURL(str) {
  var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
    '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
    '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
    '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
    '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
    '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
  return !!pattern.test(str);
}

我建议使用锚元素,而不是使用正则表达式。

当你设置一个锚的href属性时,其他各种属性也会被设置。

var parser = document.createElement('a');
parser.href = "http://example.com:3000/pathname/?search=test#hash";

parser.protocol; // => "http:"
parser.hostname; // => "example.com"
parser.port;     // => "3000"
parser.pathname; // => "/pathname/"
parser.search;   // => "?search=test"
parser.hash;     // => "#hash"
parser.host;     // => "example.com:3000"

但是,如果href绑定的值不是一个有效的url,那么这些辅助属性的值将是空字符串。

编辑:正如评论中指出的:如果使用了无效的url,则可以替换当前url的属性。

所以,只要你没有传递当前页面的URL,你可以这样做:

function isValidURL(str) {
   var a  = document.createElement('a');
   a.href = str;
   return (a.host && a.host != window.location.host);
}