捕获被特殊字符嵌套/包含的正则表达式组

4

我正在尝试搜索出现在波浪线(~)符号边界内的单词。

 e.g. ~albert~ is a ~good~ boy.

我知道可以使用~.+?~来实现,而且这对我已经有效了。但是有些特殊情况下,我需要匹配嵌套的波浪号句子。

 e.g. ~The ~spectacle~~ was ~broken~

在上面的例子中,我必须分别捕获“ The Spectacle”,“spectacle”和“broken”。这些将逐字翻译或附带冠词(An,The,whatever)进行翻译。原因是在我的系统中:
1) 'The spectacle' requires a separate translation on a specific cases.
2) 'Spectacle' also needs translation on specific cases.
3) IF a tranlsation exist for The spectacle, we will use that, ELSE 
   we will use 

另一个用来解释的例子是:

 ~The ~spectacle~~ was ~borken~, but that was not the same ~spectacle~ 
  that was given to ~me~.

在上面的例子中,我将会有翻译:
 1) 'The spectacle' (because the translation case exists for 'The spectacle', otherwise I would've only translated spectacle on it's own)
 2) 'broken'
 3) 'spectacle'
 4) me

我在尝试组合一个表达式,以确保它被捕获在我的正则表达式中。到目前为止,我成功使用的是“〜.+?〜”。但我知道通过某种形式的前瞻或后顾,我可以让它工作。有人能帮我吗?

最重要的方面是回归测试,这将确保现有内容不会被破坏。如果我成功了,我会发布它。

N.B. 如果有帮助的话,当前只有一级嵌套需要分解。所以,“〜The ~spectacle~~”将是最深层次(直到我需要更多!)


我认为第二个例子也应该返回“broken”。 - Wiktor Stribiżew
除非您可以将嵌套深度限制为固定值,否则您需要一个能够处理递归的正则表达式引擎。您正在使用哪一个? - Tim Pietzcker
@stribizhev 你是对的,现在更新正文。 - ha9u63a7
@TimPietzcker 我将在Java中使用它。但我认为这可能是一个正则表达式特定的问题,所以没有用java标记它。 - ha9u63a7
3
所有正则表达式问题都需要附上语言标签(请参阅 标签信息)。很抱歉,在 Java 正则表达式中无法使用递归。 - Tim Pietzcker
这不是一个常规语言,应该使用解析器而不仅仅是正则表达式来解决。 - emartinelli
2个回答

2

我有段时间前写了类似这样的东西,虽然没有进行过太多测试:

(~(?(?=.*?~~.*?~).*?~.*?~.*?~|[^~]+?~))

或者

(~(?(?=.*?~[A-Za-z]*?~.*?~).*?~.*?~.*?~|[^~]+?~))

RegEx101

Another alternative

(~(?:.*?~.*?~){0,2}.*?~)
                 ^^ change to max depth

哪个方法最好就用哪个

如果要添加更多的内容,请在两处看到一堆.*?~时添加几组额外的内容。

主要问题

如果我们允许无限嵌套,我们怎么知道它何时结束和开始?一个笨拙的图表:

~This text could be nested ~ so could this~ and this~ this ~Also this~
|                          |              |_________|      |         |
|                          |_______________________________|         |
|____________________________________________________________________|

或者:

~This text could be nested ~ so could this~ and this~ this ~Also this~
|                          |              |         |      |_________|
|                          |______________|         |
|___________________________________________________|

编译器无法确定选择哪一个

对于你的句子

~The ~spectacle~~ was ~broken~, but that was not the same ~spectacle~ that was given to ~me~.
|    |         ||_____|      |                            |         |
|    |         |_____________|                            |         |
|    |____________________________________________________|         |
|___________________________________________________________________|

或者:

~The ~spectacle~~ was ~broken~, but that was not the same ~spectacle~ that was given to ~me~.
|    |_________||     |______|                            |_________|                   |__|
|_______________|

我该怎么做?

使用交替字符(如@tbraun所建议的)以便编译器知道开始和结束的位置:

{This text can be {properly {nested}} without problems} because {the compiler {can {see {the}}} start and end points} easily. Or use a compiler:

注意:我不太擅长Java,因此有些代码可能不正确

import java.util.List;

String[] chars = myString.split('');
int depth = 0;
int lastMath = 0;
List<String> results = new ArrayList<String>();

for (int i = 0; i < chars.length; i += 1) {
    if (chars[i] === '{') {
        depth += 1;
        if (depth === 1) {
            lastIndex = i;
        }
    }
    if (chars[i] === '}') {
        depth -= 1;
        if (depth === 0) {
            results.add(StringUtils.join(Arrays.copyOfRange(chars, lastIndex, i + 1), ''));
        }
        if (depth < 0) {
            // Balancing problem Handle an error
        }
    }
}

这里使用了StringUtils


根据我的测试,如果您有三层或更多层的波浪线,这将无法正常工作。 - Voidpaw
1
@Voidpaw说他只会有一个层。 - Downgoat
1
他还特别强调说:“直到我需要更多!!!”所以无论有多少层,我们都应该尝试解决这个问题。 - Voidpaw
1
@tbraun 我提到了你 :) - Downgoat

-1

你需要一些东西来区分开始/结束模式。例如{}

然后你可以使用模式\{[^{]*?\}来排除{

{The {spectacle}} was {broken}

第一次迭代

{spectacle}
{broken}

第二次迭代

{The spectacle}

为什么要踩我?我发布帖子后,有其他解决方案更新了,指出真正的解决方案是使用替代字符 {},我不应该因为提供实际解决方案而受到惩罚。 - tbraun

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