【问题标题】:regex - How to match elements while ignoring others between quotation marks?regex - 如何匹配元素而忽略引号之间的其他元素?
【发布时间】:2015-05-26 14:44:04
【问题描述】:

我似乎找不到适合我需要的正则表达式。

我有一个这种形式的 .txt 文件:

Abc "test" aBC : "Abc aBC" 
Brooking "ABC" sadxzc : "I am sad"
asd : "lorem"
a22 : "tactius"
testsa2 : "bruchia"
test : "Abc aBC"
b2 : "Ast2"

我希望从这个 .txt 文件中提取与该正则表达式“([a-zA-Z]\w+)”匹配的所有内容,引号之间的内容除外。

我想重命名每个单词(引号中的单词除外),所以我应该有例如以下输出:

A "test " B : "Abc aBC" 
Z "ABC" X : "I am sad"
Test : "lorem"
F : "tactius"
H : "bruchia"
Game : "Abc aBC"
S: "Ast2"

这甚至可以使用正则表达式来实现吗?有没有不使用正则表达式的替代方法?

【问题讨论】:

  • 根据您的文件格式,您似乎更想重命名冒号 (:) 之前的内容并将其单独保留...这比处理里面的所有内容更容易和引号外不同。这是一个准确的评估吗? ETA:帖子已更新,这个问题现在无关紧要,因为这显然不是一个准确的评估。
  • 这是 Json 吗?因为 Json 格式比较复杂。您最好为此使用库。
  • 好的,我用文件格式做了一个小的编辑。我正在使用 java 来完成这项任务。不,这不是 Json。
  • Abc 变成 A 和 Brooking 变成 Z?这是我们正在研究的一个非常复杂的正则表达式。
  • 是的,这正是我的想法。

标签: java regex


【解决方案1】:

如果引号是平衡的并且输入中没有转义,例如\",那么您可以使用此正则表达式来匹配双引号之外的单词:

(?=(?:(?:[^"]*"){2})*[^"]*$)(\b[a-zA-Z]\w+\b)

RegEx Demo

在java中是:

Pattern p = Pattern.compile("(?=(?:(?:[^\"]*\"){2})*[^\"]*$)(\\b[a-zA-Z]\\w+\\b)");

如果单词在双引号之外,此正则表达式将匹配单词,方法是使用前瞻确保每个匹配单词后有偶数个引号。

【讨论】:

  • 这正是我一直在寻找的,非常感谢。你只是帮了我很多。 (是的,引号是平衡的)
【解决方案2】:

一种简单的方法可能是将字符串按" 拆分,然后在每个奇数部分(如果从 1 开始编号,则在第 1、3、...部分上)使用您的正则表达式进行替换,然后加入一切都回来了。

UPD 但是,手动实现也很简单。沿着这条线走,跟踪你是否在引号内。

insideQuotes = false
result = ""
currentPart = ""
input = input + '"' // so that we do not need to process the last part separately
for ch in string
    if ch == '"'
        if not insideQuotes
            currentPart = replace(currentPart)
        result = result + currentPart + '"'
        currentPart = ""
        insideQuotes = not insideQuotes
    else 
        currentPart = currentPart + ch
drop the last symbol of result (it is that quote mark that we have added)

不过,还要考虑一下您是否需要一些更高级的语法。例如,引用转义如

word "inside quote \" still inside" outside again

?如果是,那么您将需要更高级的解析器,或者您可能会考虑使用一些特殊的格式。

【讨论】:

    【解决方案3】:

    您无法按照您的想法制定“引号内”条件。但是您可以轻松地搜索未引用的单词引用的字符串,并仅对未引用的单词执行操作:

    Pattern p = Pattern.compile("\"[^\"]*\"|([a-zA-Z]\\w+)");
    for(String s: lines) {
        Matcher m=p.matcher(s);
        while(m.find()) {
            if(m.group(1)!=null) {
                System.out.println("take action with "+m.group(1));
            }
        }
    }
    

    这利用了这样一个事实,即每次搜索下一个匹配项都从前一个匹配项的末尾开始。因此,如果您找到带引号的字符串 ("[^"]*"),您无需执行任何操作并继续搜索其他匹配项。仅当引用的字符串不匹配时,模式才会查找单词 (([a-zA-Z]\w+)),如果找到,组 1 会捕获该单词(将不是 null)。

    【讨论】:

      猜你喜欢
      • 2016-04-12
      • 2010-09-10
      • 2011-07-23
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多