1. ホーム
  2. ジャバスクリプト

[解決済み】文字列からホスト名を抽出する方法

2022-03-29 12:01:56

質問

文字列からURL全体ではなく、URLのルートだけにマッチさせたい。与えられた

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

最後の2つのインスタンスの解決を www.example.com または example.com ドメインになります。

正規表現が遅いと聞いていますし、このページで2回目の正規表現になるので、もし正規表現なしでできる方法があれば教えてください。

このソリューションのJS/jQueryバージョンを求めています。

どのように解決するのですか?

npm パッケージを使用することをお勧めします。 psl (パブリックサフィックスリスト) . public Suffix List"は、有効なすべてのドメインサフィックスとルールのリストで、国コードのトップレベルドメインだけでなく、ルートドメインとみなされるユニコード文字(つまり www.食狮.公司.cn , b.c.kobe.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;
}

// Warning: you can use this function to extract the "root" domain, but it will not be as accurate as using the psl package.

function extractRootDomain(url) {
  var domain = extractHostname(url),
  splitArr = domain.split('.'),
  arrLen = splitArr.length;

  //extracting the root domain here
  //if there is a subdomain
  if (arrLen > 2) {
    domain = splitArr[arrLen - 2] + '.' + splitArr[arrLen - 1];
    //check to see if it's using a Country Code Top Level Domain (ccTLD) (i.e. ".me.uk")
    if (splitArr[arrLen - 2].length == 2 && splitArr[arrLen - 1].length == 2) {
      //this is using a ccTLD
      domain = splitArr[arrLen - 3] + '.' + domain;
    }
  }
  return domain;
}

const urlHostname = url => {
  try {
    return new URL(url).hostname;
  }
  catch(e) { return e; }
};

const urls = [
    "http://www.blog.classroom.me.uk/index.php",
    "http://www.youtube.com/watch?v=ClkQA2Lb_iE",
    "https://www.youtube.com/watch?v=ClkQA2Lb_iE",
    "www.youtube.com/watch?v=ClkQA2Lb_iE",
    "ftps://ftp.websitename.com/dir/file.txt",
    "websitename.com:1234/dir/file.txt",
    "ftps://websitename.com:1234/dir/file.txt",
    "example.com?param=value",
    "https://facebook.github.io/jest/",
    "//youtube.com/watch?v=ClkQA2Lb_iE",
    "www.食狮.公司.cn",
    "b.c.kobe.jp",
    "a.d.kyoto.or.jp",
    "http://localhost:4200/watch?v=ClkQA2Lb_iE"
];

const test = (method, arr) => console.log(
`=== Testing "${method.name}" ===\n${arr.map(url => method(url)).join("\n")}\n`);

test(extractHostname, urls);
test(extractRootDomain, urls);
test(urlHostname, urls);

プロトコルやポート番号に関係なく、ドメインを抽出することができます。これは非常に単純化された、正規表現でない解決策なので、これで十分だと思います。

URL(url).hostname は有効な解決策ですが、私が対処したいくつかのエッジケースにはうまく対応できません。最後のテストでお分かりのように、URLのいくつかを好まないのです。しかし、私の解決策を組み合わせて使うことで、間違いなくすべてがうまくいきます。

*Timmerz, @renoirb, @rineez, @BigDong, @ra00l, @ILikeBeansTacos, @CharlesRobertsonさん、ご提案ありがとうございました! @ross-allen さん、バグを報告していただきありがとうございました