代码之家  ›  专栏  ›  技术社区  ›  donohoe

用于分析哈希标记的regex(或其他建议)

  •  3
  • donohoe  · 技术社区  · 14 年前

    我正试图解析从hashtag得到的字符串,到目前为止它看起来像一个regex 可以 做最干净的方式。模式及其解释如下:

    #p3                  -> p = 3
    #h4                  ->         h = [ 4 ]
    #h4,h6               ->         h = [ 4, 6 ]
    #p3,h4,h6            -> p = 3,  h = [ 4, 6 ]
    #h4,h6,p3            -> p = 3,  h = [ 4, 6 ]
    #h4s2,6,10           ->         h = [ 4 ],    s = { "4": [ 2, 6, 10 ] }
    #h4s2,6,10,h6s5      ->         h = [ 4, 6 ], s = { "4": [ 2, 6, 10 ] , "6": [ 5 ] }
    #p20h4s2,6,10,h6s5,1 -> p = 20, h = [ 4, 6 ], s = { "4": [ 2, 6, 10 ] , "6": [ 5, 1 ] }
    

    正如我所说的,我认为正则表达式可能是我最好的选择,但对于任何复杂的事物来说,它也是一个弱点。

    如果您有其他建议/解决方案,我欢迎他们。我可以用 if/else 有很多 indexOf splits 等等…但我相信一定有比这更好的方法。

    更新: 左边的输出最好被认为是一种解释。虽然这是期望的最终结果,但regex解决方案不必解决全部问题,但可能会让我参与其中。再说一遍,我正在 JavaScript .

    3 回复  |  直到 14 年前
        1
  •  2
  •   Jason Orendorff Oliver    14 年前

    这是一些代码。

    var p, h = [], s = {};
    
    var re = /[ph][0-9]+|s[0-9,]*[0-9]/g;
    var a;
    while ((a = re.exec(myhashtag)) !== null) {
        var first = a[0].substring(0, 1);
        var rest = a[0].substring(1);
        if (first == 'p')
            p = parseInt(rest);
        else if (first == 'h')
            h.push(parseInt(rest));
        else {
            a = rest.split(',');
            for (var i = 0; i < a.length; i++)
                a[i] = parseInt(a[i]);
            s[h[h.length - 1]] = a;
        }
    }
    

    这只使用正则表达式查找哈希标记的所有片段 p3 h4 s3,4,5 . 剩下的只是普通的javascript。

    这个代码是 非常 涣散。如果hashtag中包含无法解析的垃圾,例如 #p3_banana_*q4 ,此代码只是忽略它。如果hashtag包含这样的废话,那么编写更严格的代码来抛出错误可能会更好。

        2
  •  5
  •   Welbog    14 年前

    您可能可以使用一个表达式来确定特定行是否有效,但是如果您正试图基于输入字符串构建一个结构,那么您可能应该采用两步标记化/解析方案,因为这样做可以简化问题。

    从外观上看,您有三种类型的令牌: p , h s . 每个令牌都是一个字母,后跟一个数字(在 S )

    所以我将从一个记号赋予器开始,它被设计成将字符串转换成一系列抽象记号。每个标记都可以使用正则表达式进行匹配。

    让我们用这个字符串: #p20h4s2,6,10,h6s5,1 . 虽然还有剩余的输入,但是您将根据剩余的输入创建一个令牌序列。

    你的第一个代币是 有价值 20 . 那么你有一个 H 有价值 4 . 然后一个 S 有价值 [2,6,10] 等等。要确定哪个标记是哪个,请使用非常简单的正则表达式。 的表达式可以是 p\d+ . H 可能是 h\d+ . S 看起来应该是 s(\d+)(,\d+)* .

    标记化技术步骤的结果是这样的一系列对象: { p(20), h(4), s(2,6,10), h(6), s(5,1) } . 现在你可以决定 s(2,6,10) 是其中的一部分 h(4) 构建您的结构,而不必担心结构的字符串表示。

    现在,对于在JavaScript中实现这一点来说,这并不难。标记序列可以是一个数组,您可以使用if/else块和上面的正则表达式查找标记。

    重要的是将使用字符串表示(标记化技术)的部分和使用抽象表示(解析)的部分分开。它使概念上的事情简单得多。如果您以后需要新类型的令牌,也可以通过这种方式添加新类型的令牌。

        3
  •  0
  •   eykanal    14 年前

    正则表达式用于确定给定的模式是否存在,并可能对其起作用(替换、删除等)。您需要做的不止这些;您需要确定是否存在模式,然后根据该模式进行某种分析。如果是我,我将按如下方式执行(下面是伪代码):

    if(string_begins_with('#')) {
        if(string_contains('p')) {
            // get numbers following using some "CSV-to-array" function
        }
    
        if(string_contains('h') {
            foreach('h') {
                // check for 's' following, do csv-to-array thing
            }
        }
    }
    

    编辑:如果你真的想走这条路,你必须使用lookaheads。假设 p 固定在开头:

    /
    ^\#
    (p[\d,]+)?   # find the 'p'
    (            # beginning of 'find the "h"' code
        h([[0-9],])  # find the 'h'
        (?=          # beginning of lookahead for 's'
            (s([[0-9],])+)?  # code for s, including a final ? since it may not 
                             # be there at all. I'm not sure if this part will work.
        )           # end of lookahead
    )+            # end of code for 'h', + since you may have more than one 'h'
    /
    

    这可能需要一些工作,但这是一个开始。