使用正则表达式按 "." 分割字符串

5

我希望你能为我在Javascript中编写一个正则表达式。我有一个字符串:

'*window.some1.some\.2.(a.b + ")" ? cc\.c : d.n [a.b, cc\.c]).some\.3.(this.o.p ? ".mike." [ff\.]).some5'

我想按照句点拆分这个字符串,以便获得一个数组:

[
    '*window',
    'some1',
    'some\.2',   //ignore the . because it's escaped
    '(a.b ? cc\.c : d.n [a.b, cc\.c])',  //ignore everything inside ()
    'some\.3',
    '(this.o.p ? ".mike." [ff\.])',
    'some5'
]

什么正则表达式可以完成这个任务?

{foo.bar}是什么情况? - Mark Byers
1
你想用这个做什么?听起来你想要比正则表达式更强大的东西... - hugomg
也许可以查看这个链接:https://dev59.com/CHRA5IYBdhLWcg3w0xjk#812236? - Brad Koch
拆分操作始终会返回一个简单的字符串或者带有括号的内容,因此我永远不会得到 {foo.bar}。 - user1031396
3
朋友,你需要一个完整的解析器... - Kenan Banks
5个回答

7
var string = '*window.some1.some\\.2.(a.b + ")" ? cc\\.c : d.n [a.b, cc\\.c]).some\\.3.(this.o.p ? ".mike." [ff\\.]).some5';
var pattern = /(?:\((?:(['"])\)\1|[^)]+?)+\)+|\\\.|[^.]+?)+/g;
var result = string.match(pattern);
result = Array.apply(null, result); //Convert RegExp match to an Array

Fiddle: http://jsfiddle.net/66Zfh/3/
正则表达式的解释。匹配一个连续的字符集,要求满足:

/             Start of RegExp literal
(?:            Create a group without reference (example: say, group A)
   \(          `(` character
   (?:         Create a group without reference (example: say, group B)
      (['"])     ONE `'` OR `"`, group 1, referable through `\1` (inside RE)
      \)         `)` character
      \1         The character as matched at group 1, either `'` or `"`
     |          OR
      [^)]+?     Any non-`)` character, at least once (see below)
   )+          End of group (B). Let this group occur at least once
  |           OR
   \\\.        `\.` (escaped backslash and dot, because they're special chars)
  |           OR
   [^.]+?      Any non-`.` character, at least once (see below)
)+            End of group (A). Let this group occur at least once
/g           "End of RegExp, global flag"
        /*Summary: Match everything which is not satisfying the split-by-dot
                 condition as specified by the OP*/

单个加号 + 和加号和问号 +? 之间有区别。单个加号尝试匹配尽可能多的字符,而 +? 则仅匹配必要的字符以获取 RegExp 匹配结果。例如:123 使用 \d+? > 1 和 \d+ > 123

String.match 方法执行全局匹配,因为使用了全局标志 /g。带有 g 标志的 match 函数返回一个由所有匹配子序列组成的数组。

当省略 g 标志时,只会选择第一个匹配项。数组将包含以下元素:

Index 0: <Whole match>
Index 1: <Group 1>

Rob W,<BR> 看起来这可能是解决方案。<BR>对字符串进行轻微更改,添加')'<BR> *window.some1.some.2.(a.b + ")" + ')' ? cc.c : d.n [a.b, cc.c]).some.3.(this.o.p ? ".mike." [ff.]).some5 - user1031396
@RobW 谢谢。重写上面的评论。稍微更改字符串,在要分割的字符串中添加 ')'。*window.some1.some.2.(a.b + ")" + ')' ? cc.c : d.n [a.b, cc.c]).some.3.(this.o.p ? ".mike." [ff.]).some5 - user1031396
你的意思是什么?当前表达式按照问题要求返回结果。如果你想要额外的功能,请创建一个新问题,并链接到这个问题,因为当前的答案是针对你当前的问题的。 - Rob W
@Rob W,你能否请发一份正则表达式的解释?这将有助于我在未来进行维护。 - user1031396
@Rob W,非常感谢。 - user1031396
显示剩余5条评论

3
下面的正则表达式:
result = subject.match(/(?:(\(.*?[^'"]\)|.*?[^\\])(?:\.|$))/g);

可以用来获取所需的结果。由于您想要省略.,因此组1具有结果。

使用以下方法:

var myregexp = /(?:(\(.*?[^'"]\)|.*?[^\\])(?:\.|$))/g;
var match = myregexp.exec(subject);
while (match != null) {
    for (var i = 0; i < match.length; i++) {
        // matched text: match[i]
    }
    match = myregexp.exec(subject);
}

解释:

// (?:(\(.*?[^'"]\)|.*?[^\\])(?:\.|$))
// 
// Match the regular expression below «(?:(\(.*?[^'"]\)|.*?[^\\])(?:\.|$))»
//    Match the regular expression below and capture its match into backreference number 1 «(\(.*?[^'"]\)|.*?[^\\])»
//       Match either the regular expression below (attempting the next alternative only if this one fails) «\(.*?[^'"]\)»
//          Match the character “(” literally «\(»
//          Match any single character that is not a line break character «.*?»
//             Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
//          Match a single character NOT present in the list “'"” «[^'"]»
//          Match the character “)” literally «\)»
//       Or match regular expression number 2 below (the entire group fails if this one fails to match) «.*?[^\\]»
//          Match any single character that is not a line break character «.*?»
//             Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
//          Match any character that is NOT a “A \ character” «[^\\]»
//    Match the regular expression below «(?:\.|$)»
//       Match either the regular expression below (attempting the next alternative only if this one fails) «\.»
//          Match the character “.” literally «\.»
//       Or match regular expression number 2 below (the entire group fails if this one fails to match) «$»
//          Assert position at the end of the string (or before the line break at the end of the string, if any) «$»

你的解决方案也可以,但是最后留下了一个句号。谢谢。 - user1031396

2

使用正则表达式进行平衡括号匹配是非常困难的,特别是在JavaScript中。

最好创建自己的解析器。以下是一种聪明的方法,可以利用正则表达式的优势:

  • 创建一个匹配并捕获任何“感兴趣的模式”的正则表达式- /(?:(\\.)|([\(\[\{])|([\)\]\}])|(\.))/g
  • 使用string.replace(pattern, function (...)),在函数中保持开放和关闭大括号的计数。
  • 将匹配的文本添加到缓冲区。
  • 如果找到分割字符且开放和关闭括号平衡,则将缓冲区添加到结果数组中。

这个解决方案需要一些工作,并且需要闭包的知识,您应该查看string.replace的文档,但我认为这是解决您问题的好方法!

更新: 在注意到与此相关的问题数量后,我决定接受上述挑战。 这里是使用正则表达式拆分字符串的实时代码。 该代码具有以下功能:
  • 使用正则表达式模式查找拆分
  • 只有在存在平衡括号时才进行拆分
  • 只有在存在平衡引号时才进行拆分
  • 允许使用\转义括号、引号和拆分
这段代码将完美地适用于您的示例。

0

这项工作不需要正则表达式。

var s = '*window.some1.some\.2.(a.b + ")" ? cc\.c : d.n [a.b, cc\.c]).some\.3.(this.o.p ? ".mike." [ff\.]).some5';

console.log(s.match(/(?:\([^\)]+\)|.*?\.)/g));

输出:

  ["*window.", "some1.", "some.", "2.", "(a.b + ")", "" ? cc.", "c : d.", "n [a.", "b, cc.", "c]).", "some.", "3.", "(this.o.p ? ".mike." [ff.])", "."]

1
这似乎不符合问题的要求(忽略 \.,并忽略括号内的 ....) - Greg Hewgill
然而,这并不是原帖作者想要的。原帖作者希望括号内的文本将作为一个单元保留(即使其中有点),并且转义点(/.)也应被忽略。 - Madara's Ghost
这是我第一次在Stackflow上发布问题,对于快速的回复感到惊讶。感谢Stackflow和所有回答我的人。 - user1031396

0

所以,我正在处理这个问题,现在我发现@FailedDev并不是一个失败者,因为他做得很好。 :)

无论如何,这是我的解决方案。我只会发布正则表达式。

((\(.*?((?<!")\)(?!")))|((\\\.)|([^.]))+)

不幸的是,在您的情况下,这种方法不起作用,因为我正在使用负回顾后断言,而我认为它不受JavaScript正则表达式引擎支持。然而,在其他引擎中,它应该按预期工作,可以在此处http://gskinner.com/RegExr/进行确认。替换为$1\n。


正如您所提到的,您正在使用回顾后发现,这在JavaScript中不受支持。即使支持回顾后发现,?!也必须是?=(前瞻)。 - Rob W
不,我想要的是负向回顾,而不是向前查找。我想匹配的是没有被"字符预置的)字符 => 负向回顾。 - Gaute Løken
жҲ‘жҢҮзҡ„жҳҜ ?!пјҲдҪҚдәҺ \)(?!)гҖӮжӮЁжғіеҢ№й…ҚдёҖдёӘз”ұеҸҢеј•еҸ·еүҚеҗҺзјҖзҡ„жӢ¬еҸ·гҖӮ - Rob W
在这种情况下,我想要结束我的匹配,即第一个未被双引号括起来的)。因此,我想匹配一个括号,它既不是由双引号字符前缀也不是后缀的。所以我的推理是正确的。然而,我确实看到了一个错误,但我不会指出给你,因为你在挑衅我。 :) - Gaute Løken

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接