[javascript] 문자열에서 호스트 이름 이름 추출

텍스트 문자열의 전체 URL이 아닌 URL의 루트와 일치시키고 싶습니다. 주어진:

http://www.youtube.com/watch?v=ClkQA2Lb_iE
http://youtu.be/ClkQA2Lb_iE
http://www.example.com/12xy45
http://example.com/random

www.example.com또는 2 개의 마지막 인스턴스를 example.com도메인으로 해결하려고 합니다.

나는 정규 표현식이 느리다는 것을 들었고 이것이 페이지의 두 번째 정규 표현식이 될 것이므로 정규 표현식없이 할 수 있다면 알려주십시오.

이 솔루션의 JS / jQuery 버전을 찾고 있습니다.



답변

npm 패키지 psl (Public Suffix List)을 사용하는 것이 좋습니다 . “공개 접미사 목록”은 국가 코드 최상위 도메인뿐만 아니라 루트 도메인으로 간주 될 유니 코드 문자 (예 : www. 食 狮. 公司 .cn, bckobe)의 모든 유효한 도메인 접미사 및 규칙 목록입니다. .jp 등). 자세한 내용은 여기를 참조 하십시오 .

시험:

npm install --save psl

그런 다음 “extractHostname”구현으로 다음을 실행하십시오.

let psl = require('psl');
let url = 'http://www.youtube.com/watch?v=ClkQA2Lb_iE';
psl.get(extractHostname(url)); // returns youtube.com

npm 패키지를 사용할 수 없으므로 아래에서 extractHostname 만 테스트하십시오.

function extractHostname(url) {
    var hostname;
    //find & remove protocol (http, ftp, etc.) and get hostname

    if (url.indexOf("//") > -1) {
        hostname = url.split('/')[2];
    }
    else {
        hostname = url.split('/')[0];
    }

    //find & remove port number
    hostname = hostname.split(':')[0];
    //find & remove "?"
    hostname = hostname.split('?')[0];

    return hostname;
}

//test the code
console.log("== Testing extractHostname: ==");
console.log(extractHostname("http://www.blog.classroom.me.uk/index.php"));
console.log(extractHostname("http://www.youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractHostname("https://www.youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractHostname("www.youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractHostname("ftps://ftp.websitename.com/dir/file.txt"));
console.log(extractHostname("websitename.com:1234/dir/file.txt"));
console.log(extractHostname("ftps://websitename.com:1234/dir/file.txt"));
console.log(extractHostname("example.com?param=value"));
console.log(extractHostname("https://facebook.github.io/jest/"));
console.log(extractHostname("//youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractHostname("http://localhost:4200/watch?v=ClkQA2Lb_iE"));

프로토콜이나 포트 번호가 있더라도 도메인을 추출 할 수 있습니다. 이것은 매우 단순화 된 비 정규식 솔루션이므로 그렇게 할 것이라고 생각합니다.

* 귀하의 제안에 대해 @Timmerz, @renoirb, @rineez, @BigDong, @ ra00l, @ILikeBeansTacos, @CharlesRobertson에게 감사드립니다! @ ross-allen, 버그를보고 해 주셔서 감사합니다!


답변

정규 표현식을 사용하지 않는 깔끔한 트릭 :

var tmp        = document.createElement ('a');
;   tmp.href   = "http://www.example.com/12xy45";

// tmp.hostname will now contain 'www.example.com'
// tmp.host will now contain hostname and port 'www.example.com:80'

위와 같은 함수로 위를 감싸면 도메인 부분을 URI에서 빼내는 가장 좋은 방법이 있습니다.

function url_domain(data) {
  var    a      = document.createElement('a');
         a.href = data;
  return a.hostname;
}


답변

문자열을 구문 분석 할 필요가 없으며 URL을 URL생성자에 인수로 전달하면됩니다 .

var url = 'http://www.youtube.com/watch?v=ClkQA2Lb_iE';
var hostname = (new URL(url)).hostname;

assert(hostname === 'www.youtube.com');


답변

이 시도:

var matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
var domain = matches && matches[1];  // domain will be null if no match is found

결과에서 포트를 제외하려면이 표현식을 대신 사용하십시오.

/^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)/i

편집 : 특정 도메인이 일치하지 않도록하려면 부정적 예측을 사용하십시오.(?!youtube.com)

/^https?\:\/\/(?!(?:www\.)?(?:youtube\.com|youtu\.be))([^\/:?#]+)(?:[\/:?#]|$)/i


답변

포트 번호와 특수 문자를 사용할 수 있으므로 URL 구문 분석이 까다로울 수 있습니다. 따라서 parseUri 와 같은 것을 사용 하여이 작업 을 수행하는 것이 좋습니다 . 수백 개의 URL을 구문 분석하지 않으면 성능이 문제가 될 것입니다.


답변

2020 답변

이에 대한 추가 종속성이 필요하지 않습니다! 성능을 최적화해야하는지 여부에 따라 두 가지 좋은 솔루션이 있습니다.

URL.hostname가독성을 위해 사용

바벨 시대에 가장 깨끗하고 쉬운 해결책은를 사용하는 것 URL.hostname입니다.

const getHostname = (url) => {
  // use URL constructor and return hostname
  return new URL(url).hostname;
}

// tests
console.log(getHostname("/programming/8498592/extract-hostname-name-from-string/"));
console.log(getHostname("https://developer.mozilla.org/en-US/docs/Web/API/URL/hostname"));

URL.hostnameURL API의 일부이며 IE ( caniuse )를 제외한 모든 주요 브라우저에서 지원됩니다 . 레거시 브라우저를 지원해야하는 경우 URL 폴리 필을 사용하십시오 .

이 솔루션을 사용하면 다른 URL 속성 및 메소드에 액세스 할 수도 있습니다 . 예를 들어 URL의 경로 이름 또는 쿼리 문자열 params 도 추출하려는 경우에 유용합니다 .


성능을 위해 RegEx 사용

URL.hostname앵커 솔루션 또는 parseUri를 사용하는 것보다 빠릅니다 . 그러나 여전히 gilly3의 정규 표현식 보다 훨씬 느립니다 .

const getHostnameFromRegex = (url) => {
  // run against regex
  const matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
  // extract hostname (will be null if no match is found)
  return matches && matches[1];
}

// tests
console.log(getHostnameFromRegex("/programming/8498592/extract-hostname-name-from-string/"));
console.log(getHostnameFromRegex("https://developer.mozilla.org/en-US/docs/Web/API/URL/hostname"));

jsPerf에서 직접 테스트하십시오.

많은 수의 URL을 처리해야하는 경우 (성능이 중요한 경우)이 솔루션을 대신 사용하는 것이 좋습니다. 그렇지 않으면 URL.hostname가독성을 선택하십시오 .


답변

나는 주어진 솔루션을 사용하려고 시도했는데, 선택된 솔루션은 내 목적을 위해 과잉이었고 “요소 만들기”는 나를 엉망으로 만듭니다.

아직 URL에 포트가 준비되지 않았습니다. 누군가가 유용하다고 생각하기를 바랍니다.

function parseURL(url){
    parsed_url = {}

    if ( url == null || url.length == 0 )
        return parsed_url;

    protocol_i = url.indexOf('://');
    parsed_url.protocol = url.substr(0,protocol_i);

    remaining_url = url.substr(protocol_i + 3, url.length);
    domain_i = remaining_url.indexOf('/');
    domain_i = domain_i == -1 ? remaining_url.length - 1 : domain_i;
    parsed_url.domain = remaining_url.substr(0, domain_i);
    parsed_url.path = domain_i == -1 || domain_i + 1 == remaining_url.length ? null : remaining_url.substr(domain_i + 1, remaining_url.length);

    domain_parts = parsed_url.domain.split('.');
    switch ( domain_parts.length ){
        case 2:
          parsed_url.subdomain = null;
          parsed_url.host = domain_parts[0];
          parsed_url.tld = domain_parts[1];
          break;
        case 3:
          parsed_url.subdomain = domain_parts[0];
          parsed_url.host = domain_parts[1];
          parsed_url.tld = domain_parts[2];
          break;
        case 4:
          parsed_url.subdomain = domain_parts[0];
          parsed_url.host = domain_parts[1];
          parsed_url.tld = domain_parts[2] + '.' + domain_parts[3];
          break;
    }

    parsed_url.parent_domain = parsed_url.host + '.' + parsed_url.tld;

    return parsed_url;
}

이것을 실행 :

parseURL('https://www.facebook.com/100003379429021_356001651189146');

결과:

Object {
    domain : "www.facebook.com",
    host : "facebook",
    path : "100003379429021_356001651189146",
    protocol : "https",
    subdomain : "www",
    tld : "com"
}