Javascript中的通配符字符串比较

IT技术 javascript string comparison
2021-03-19 22:52:57

假设我有一个包含许多 Strings Called 的数组"birdBlue""birdRed"以及一些其他的动物,如"pig1", "pig2")。

现在我运行一个遍历数组的 for 循环,应该返回所有的鸟。什么比较在这里有意义?

Animals == "bird*"是我的第一个想法,但不起作用。有没有办法使用运算符 * (或者是否有类似的用法?

6个回答

我认为您的意思是“*”(星号)作为通配符,例如:

  • "a*b" => 以 "a" 开头并以 "b" 结尾的所有内容
  • "a*" => 以 "a" 开头的所有内容
  • "*b" => 以 "b" 结尾的所有内容
  • "*a*" => 包含 "a" 的所有内容
  • "*a*b*"=> 包含“a”的所有内容,然后是任何内容,然后是“b”,然后是任何内容

或在您的示例中:“bird*” => 以bird 开头的所有内容

我遇到了类似的问题,并用 RegExp 编写了一个函数:

//Short code
function matchRuleShort(str, rule) {
  var escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
  return new RegExp("^" + rule.split("*").map(escapeRegex).join(".*") + "$").test(str);
}

//Explanation code
function matchRuleExpl(str, rule) {
  // for this solution to work on any string, no matter what characters it has
  var escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");

  // "."  => Find a single character, except newline or line terminator
  // ".*" => Matches any string that contains zero or more characters
  rule = rule.split("*").map(escapeRegex).join(".*");

  // "^"  => Matches any string with the following at the beginning of it
  // "$"  => Matches any string with that in front at the end of it
  rule = "^" + rule + "$"

  //Create a regular expression object for matching string
  var regex = new RegExp(rule);

  //Returns true if it finds a match, otherwise it returns false
  return regex.test(str);
}

//Examples
alert(
    "1. " + matchRuleShort("bird123", "bird*") + "\n" +
    "2. " + matchRuleShort("123bird", "*bird") + "\n" +
    "3. " + matchRuleShort("123bird123", "*bird*") + "\n" +
    "4. " + matchRuleShort("bird123bird", "bird*bird") + "\n" +
    "5. " + matchRuleShort("123bird123bird123", "*bird*bird*") + "\n" +
    "6. " + matchRuleShort("s[pe]c 3 re$ex 6 cha^rs", "s[pe]c*re$ex*cha^rs") + "\n" +
    "7. " + matchRuleShort("should not match", "should noo*oot match") + "\n"
);


如果您想阅读有关所用函数的更多信息:

@ThadeuLuz:是的,你是对的。谢谢您的帮助!我已经用 split.join 解决方案(而不是 /\*/g 全局选项)替换了 .replaced 。我还添加了一些涵盖 *a* 案例的示例。
2021-04-29 22:52:57
@ThadeuLuz:那不正确。Javascript 的 .replace() 采用正则表达式并替换找到的所有匹配正则表达式的字符 => w3schools.com/jsref/jsref_replace.asp
2021-05-05 22:52:57
@Spen,您的回答让我了解了大部分情况,但是如果您使用的是 url,则可能会出现误报。例如matchRuleShort("https://evil.com", "https://*.il.com)评估为真!为了防止这种情况,我不得不使用转义的等价物转义所有非 * 字符。return new RegExp("^" + rule.replace(/[.?+^$[\]\\(){}|-]/g, "\\$&");.split("*").join(".*") + "$").test(str);stackoverflow.com/a/2593661/238638借来的正则表达式
2021-05-17 22:52:57
这个答案有一个潜在的问题。Javascript 的 .replace() 在第一个参数上带有字符串只会替换找到的第一个字符,因此第 4 个示例 *a* 将不起作用。您可以使用 .replace(/\*/g, '.*') 替换所有 *s
2021-05-18 22:52:57
第一个参数上没有字符串,就像在行 <rule = rule.replace("*", ".*");> 自己看:<"world world".replace("world", "hello" )>
2021-05-19 22:52:57

您应该使用 RegExp(它们很棒)一个简单的解决方案是:

if( /^bird/.test(animals[i]) ){
    // a bird :D
}

此函数将通配符转换为正则表达式并进行测试(它支持.通配符*

function wildTest(wildcard, str) {
  let w = wildcard.replace(/[.+^${}()|[\]\\]/g, '\\$&'); // regexp escape 
  const re = new RegExp(`^${w.replace(/\*/g,'.*').replace(/\?/g,'.')}$`,'i');
  return re.test(str); // remove last 'i' above to have case sensitive
}

类型错误:wildcard.replace 不是函数
2021-04-29 22:52:57
@DanPalmieri 通配符必须是一个字符串(所有字符串都有replace功能)——可能你有数字。看看里面的片段 - 有例子
2021-05-06 22:52:57

您可以使用 Javascript 的substring方法。例如:

var list = ["bird1", "bird2", "pig1"]

for (var i = 0; i < list.length; i++) {
  if (list[i].substring(0,4) == "bird") {
   console.log(list[i]);
  }
}

哪些输出:

bird1
bird2

基本上,您正在检查数组中的每个项目以查看前四个字母是否为“鸟”。这确实假设“鸟”将始终位于字符串的前面。


因此,假设您从 URL 获取路径名:

假设您在 Bird1?=letsfly - 您可以使用此代码检查 URL:

var listOfUrls = [
                  "bird1?=letsfly",
                  "bird",
                  "pigs?=dontfly",
                 ]

for (var i = 0; i < list.length; i++) {
  if (listOfUrls[i].substring(0,4) === 'bird') {
    // do something
  }
}

以上将匹配第一个到 URL,但不匹配第三个(不是猪)。您可以轻松地url.substring(0,4)使用正则表达式或其他 javascript 方法(如 .contains())进行替换


使用该.contains()方法可能更安全一些。您不需要知道 URL 'bird' 的哪一部分。例如:

var url = 'www.example.com/bird?=fly'

if (url.contains('bird')) {
  // this is true
  // do something
}
我的问题是相反。一方面,我在数组中有很多不同的 url(基本上都应该是像Bird1.com * 这样的RegEx 表达式,需要与 document.url 进行比较。所以要么我应该把 /document.url*/ 作为正则表达式,我认为它不起作用,或者我应该将数组中的所有字符串作为正则表达式放在数组中,最后带有 *。我尝试了这两种方法,但两种方法都不起作用。由于 url 具有不同的长度,因此子字符串方法不是“我认为真的很好吗?:/
2021-05-02 22:52:57
我认为url.substring(0,4)将返回http所有 3. 那就是如果url变量存在 ( var url = list[i])
2021-05-05 22:52:57
啊,好收获。更新它以假设数组填充了路径名,而不是 URL。因为那不是问题的真正含义。谢谢
2021-05-15 22:52:57
感谢您的回复。在我的现实世界最终场景中,字符串将通过超链接进行,但只有结尾会有所不同。我将使用 document.URL 来比较它们,所以我不能使用 RegEx,可以吗?为了使它适合于例如:bird1应该找到/返回,bird1 PARAM = letsfly?太有什么建议?最聪明的做法是什么?
2021-05-20 22:52:57
你绝对可以使用正则表达式,但你不需要。你可以使用一些东西,真的。我刚刚更新了我的答案,这是否更接近您要查找的内容?URL 列表可以来自任何地方,包括document.url.
2021-05-20 22:52:57
var searchArray = function(arr, str){
    // If there are no items in the array, return an empty array
    if(typeof arr === 'undefined' || arr.length === 0) return [];
    // If the string is empty return all items in the array
    if(typeof str === 'undefined' || str.length === 0) return arr;

    // Create a new array to hold the results.
    var res = [];

    // Check where the start (*) is in the string
    var starIndex = str.indexOf('*');

    // If the star is the first character...
    if(starIndex === 0) {

        // Get the string without the star.
        str = str.substr(1);
        for(var i = 0; i < arr.length; i++) {

            // Check if each item contains an indexOf function, if it doesn't it's not a (standard) string.
            // It doesn't necessarily mean it IS a string either.
            if(!arr[i].indexOf) continue;

            // Check if the string is at the end of each item.
            if(arr[i].indexOf(str) === arr[i].length - str.length) {                    
                // If it is, add the item to the results.
                res.push(arr[i]);
            }
        }
    }
    // Otherwise, if the star is the last character
    else if(starIndex === str.length - 1) {
        // Get the string without the star.
        str = str.substr(0, str.length - 1);
        for(var i = 0; i < arr.length; i++){
            // Check indexOf function                
            if(!arr[i].indexOf) continue;
            // Check if the string is at the beginning of each item
            if(arr[i].indexOf(str) === 0) {
                // If it is, add the item to the results.
                res.push(arr[i]);
            }
        }
    }
    // In any other case...
    else {            
        for(var i = 0; i < arr.length; i++){
            // Check indexOf function
            if(!arr[i].indexOf) continue;
            // Check if the string is anywhere in each item
            if(arr[i].indexOf(str) !== -1) {
                // If it is, add the item to the results
                res.push(arr[i]);
            }
        }
    }

    // Return the results as a new array.
    return res;
}

var birds = ['bird1','somebird','bird5','bird-big','abird-song'];

var res = searchArray(birds, 'bird*');
// Results: bird1, bird5, bird-big
var res = searchArray(birds, '*bird');
// Results: somebird
var res = searchArray(birds, 'bird');
// Results: bird1, somebird, bird5, bird-big, abird-song

像这样的方法有一长串警告,还有一长串没有考虑的“假设”,其中一些在其他答案中提到。但是对于星形语法的简单使用,这可能是一个很好的起点。

小提琴

感谢您的精彩回复。这不是内置在 JS 中并且可以“开箱即用”使用吗?:/
2021-04-28 22:52:57
不是真的,内置的 javascript 将使用正则表达式进行模式匹配。@Davsket 的答案显示了您可以如何执行此操作,并且对您的问题的评论提供了有关如何使用 Regex 的更多详细信息。就我个人而言,对于这样的事情,我会采用正则表达式的方法,但为了专门解决您的“鸟*”格式,这个答案对于简单使用就足够了。
2021-04-30 22:52:57
好吧,我还是要说正则表达式。我很糟糕,所以我不是一个好问的人,但我向你保证,有人会知道如何在正则表达式中做到这一点,或者你可以尝试自己学习。我发现了一个有趣的库它可以将全局模式转换example: bird*为正则表达式。由 node.js 包管理器使用,因此它可能非常健壮。
2021-05-05 22:52:57
正则表达式的问题在于,在现实世界的场景中,数组的内容将是超链接,我会将它们与 (document.URL) 进行比较。假设数组中的字符串/url 是bird1.com 如果documentUrl 是bird1.com我需要返回它,但如果它是bird1.com?param=letsfly也需要返回。我如何以最有效的方式解决这个问题?:/
2021-05-10 22:52:57