【问题标题】:How to find all cats with a Regular Expressions如何使用正则表达式查找所有猫
【发布时间】:2014-02-13 01:11:54
【问题描述】:

如何使用正则表达式查找所有“猫”?

“有些人在遇到问题时会想“我知道,我会用 正则表达式。“现在他们有两个问题!” (c) 杰米·扎温斯基

请帮助我通过单个查询找到 div 中的所有“猫”:)

cat
<div>let's try to find this cat and this cat</div>
cat
<div>let's try to find this cat and this cat</div>
cat

我已经这样做了,但它不起作用:

(?<=<div>)((?!<\/div>)(cat|(?:.|\n))+)(?=<\/div>)

Debuggex Demo

我在使用 Sublime Text 时发现了这个问题。我们只能进行一次查询。可能吗?如果您可以使用任何编程语言(Python、PHP、JavaScript)回答,我也会很高兴。谢谢!

我可以找到最后一只猫或第一只猫,但需要找到坐在某些 DIV 中的所有猫。我想其他语言的东西可能有可能,但我只想要一个查询(一行)——这对我来说最有趣。如果不可能,对不起我的帖子:)

感谢@revo!非常好的变体,适用于 Sublime Text。 让我为这个主题添加第二个问题...... Сan 我们对“猫”类的 div 这样做,但对“狗”类的 div 不这样做?

cat
<div class="cats">black cat, white cat</div>
cat
<div class="dogs">black cat, white cat</div>
cat

【问题讨论】:

  • 你真的只想要“猫”这个词还是整个标签?
  • olgash,是的,所有的猫都隐藏在 div 中 :)
  • 查找“cat”出现的最简单的正则表达式是……cat。除非您指定其他要求,否则没有理由让它变得更复杂。
  • 在解析任何 XML 文档(HTML 或其他)时,正则表达式通常是不适合这项工作的工具。几乎没有办法编写一个匹配cats 和&lt;div&gt;s 的所有可能排列的正则表达式(例如,@casimir-et-hippolyte 下面的答案将无法通过此测试:&lt;div&gt;&lt;div&gt;&lt;/div&gt;cat&lt;/div&gt;)。

标签: javascript python html regex sublimetext2


【解决方案1】:

这不能使用正则表达式可靠地完成(正如其他人提到的那样)。

原因是 HTML 可以包含嵌套标签,但正则表达式无法“计算”您的深度有多少层,因此您将总是能够构造一些示例您的正则表达式无法找到所有猫的 HTML 示例。

为了解析 HTML,您需要使用 STACK 来跟踪您在标签中的深度。在这个 python 示例中,我使用序列 (self.tags) 作为堆栈:

from HTMLParser import HTMLParser
import re

# create a subclass and override the handler methods
class MyHTMLParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.tags = []

    def handle_starttag(self, tag, attrs):
        self.tags.append(tag)

    def handle_endtag(self, tag):
        self.tags.pop()

    def handle_data(self, data):
        if self.tags and self.tags[-1] == 'div':
            # now we are dealing with a single string.
            # use a regular expression to find all cats
            num = len(re.findall('cat', data))
            if num:
                print 'found %d cats at %s' % (num, '.'.join(self.tags))

# instantiate the parser and fed it some HTML
parser = MyHTMLParser()
parser.feed('''
cat
<div>let's try to find this cat and this cat</div>
cat
<div>let's try to find this cat and this cat</div>
cat
''')

# now try a trickier example
parser.feed('''<body><div>cat<div>another text</div></div></body>''')

输出:

found 2 cats at div
found 2 cats at div
found 1 cats at body.div

这也很容易扩展到仅匹配基于类属性的特定 div。 (参见 handle_starttagattrs 参数)。

【讨论】:

    【解决方案2】:

    这适用于 Sublime Text:

    (?s)(cat)(?=[^>]*?</div>)
    

    【讨论】:

    • 让我们试着找到这只猫和这只猫
      你好,我是一只猫
      让我们试着找到这只猫和这只猫
    • 好的,非常感谢!现在它对我来说是最有用的答案,而且真的很管用
    • 那就再问一个问题吧! Сan 我们为某些类的 div 做它,而不是另一个 div? cat
      cat
      cat
      cat
      cat
    • 对于&lt;div&gt;cat&lt;div&gt;another text&lt;/div&gt;&lt;/div&gt;,此正则表达式失败。有人提到用正则表达式解析 Html/XML 之类的递归结构不起作用吗?
    【解决方案3】:

    考虑到您没有指定需要使用哪种语言,我将使用 JavaScript 来解决此问题。

    你可以用一个简单的技巧来清除所有垃圾:

    var string = "<div>let's try to find this cat and this cat</div>\n<div>let's try to find this cat and this cat</div>\nanother cat";
    var str = string.replace(/(^|<\/div>)[\w\W]*?(<div>|$)/g,''); //filters out anything outside divs
    console.log(str.match(/cat/g)); // ["cat", "cat", "cat", "cat"]
    

    在一行中,这将是:

    console.log("<div>let's try to find this cat and this cat</div>\n<div>let's try to find this cat and this cat</div>\nanother cat".replace(/(^|<\/div>)[\w\W]*?(<div>|$)/g,'').match(/cat/g)); // ["cat", "cat", "cat", "cat"]
    

    即使在您需要匹配以下内容时也能做到这一点:

    <div class="foo"><div></div>cat</div>
    

    我会使用以下内容:

    var str = "<div>let's try to find this cat and this cat</div>\n<div>let's try to find this cat and this cat</div>\nanother cat\n<div class=\"foo\"><div></div>and a cat</div>";
    var openCounter = 0;
    var result = [];
    for (var i=0;i<str.length;i++) {
        if (str.substr(i,4) == '<div') openCounter++;
        else if (str.substr(i,6) == '</div>') openCounter = Math.max(0,openCounter-1); //don't go lower than 0
        if (openCounter > 0 && str.substr(i,3) == 'cat') result.push([str.substr(i,3), i]);
    }
    console.log(JSON.stringify(result)); //[["cat",28],["cat",41],["cat",79],["cat",92],["cat",148]]
    

    这还会获取在字符串中找到猫的索引,并将其与猫一起存储在 result 变量中。

    【讨论】:

    • 谢谢!我可以用一个查询来做到这一点吗?
    • @DopusimVladimir 这就是您要找的东西吗?
    • 这也未通过测试&lt;div&gt;&lt;div&gt;&lt;/div&gt;cat&lt;/div&gt;
    • joeytje50,再次感谢您!这不是我想要的,但它是很酷的变体。让我编辑我的帖子
    • @asgallant,是的,它返回 null
    【解决方案4】:

    PHP 模式:

    $pattern = '~(?><div\b[^>]*+>|\G(?<!^))(?>[^c<]++|\Bc|c(?!at\b)|<(?!/div>))*+\Kcat~';
    preg_match_all($pattern, $subject, $matches);
    print_r($matches);
    

    图案细节:

    ~                  # pattern delimiter
    (?>                # atomic group: possible anchor
        <div\b[^>]*+>  # an opening div tag 
      |                # OR
        \G(?<!^)       # a match contiguous to a precedent match
    )
    (?>                # atomic group: all content between tags that is not "cat"
        [^c<]++        # all characters except "c" or "<"
      |                # OR
        \Bc            # "c" not preceded by a word boundary
      |                # OR
        c(?!at\b)      # "c" not followed by "at" and a word boundary
      |                # OR
        <(?!/div>)     # "<" not followed by "/div>"
    )*+                # repeat the group zero or more times
    \K                 # reset all that has been matched before from match result
    cat                # literal: cat
    ~
    

    使用 DOM:

    $dom = new DOMDocument();
    @$dom->loadHTML($yourHtml);
    $divs = $dom->getElementsByTagName('div');
    foreach($divs as $div) {
        preg_match_all('~\bcat\b~', $div->textContent, $matches);
        print_r($matches);
    }
    

    【讨论】:

    • 感谢您的模式!但我什么也没得到 - Array ( [0] => Array ( ) )
    • 还有很长的正则表达式!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-27
    • 2017-08-09
    • 1970-01-01
    • 2011-04-25
    相关资源
    最近更新 更多