【问题标题】:Split complicated strings using Java and Regex使用 Java 和 Regex 拆分复杂的字符串
【发布时间】:2013-05-01 17:29:55
【问题描述】:

使用 Java 和正则表达式,我想从一行文本中提取字符串。 文本可以采用以下格式 -

  1. key1(value1) key2(value2)
  2. key1(value1) key2
  3. key1 key2(value2)
  4. key1 key2
  5. key1

当使用 Type #1 时,我能够成功提取键和值,我可以使用空格分割文本,然后使用以下模式来提取键

Pattern p = Pattern.compile("\\((.*?)\\)",Pattern.DOTALL);

一个复杂的代码逻辑,用于计算“(”的出现并将其与出现的匹配 该空间可用于案例#2 和案例#3,但是,代码变得太长了。当值中也存在空格时,会出现多种复杂情况,因为这样分割文本就会成为问题。

是否有更好的正则表达式拆分/保留可以用于上述选择性案例?

【问题讨论】:

  • 您是否假设键和值中没有括号?
  • 是的@merlin2011,它们的键和值本身没有括号。

标签: java regex split


【解决方案1】:

考虑以下通用正则表达式的 powershell 示例。

(?<=^|[\s)\n])[\n]*([^(\n\s]*)([(]([^)\n]*)[)])?

示例

    $Matches = @()
    $String = 'key1(value1) key2(value2)
key3(value3) key3.5
key4 key5(value5)  GoofyStuff(I like kittens)
key6 key7 ForReal-Things(be sure to vote)
key8'
    Write-Host start with 
    write-host $String
    Write-Host
    Write-Host found
    ([regex]'(?<=^|[\s)\n])([^(\n\s]*)([(]([^)\n]*)[)])?').matches($String) | foreach {
        if ($_.Groups[1].Value) {
            write-host "key at $($_.Groups[1].Index) = '$($_.Groups[1].Value)'"
            if ($_.Groups[3].Value) {
                write-host "value at $($_.Groups[3].Index) = '$($_.Groups[3].Value)'"
                } # end if
            } # end if
        } # next match

产量

start with
key1(value1) key2(value2)
key3(value3) key3.5
key4 key5(value5)  GoofyStuff(I like kittens)
key6 key7 ForReal-Things(be sure to vote)
key8

found
key at 0 = 'key1'
value at 5 = 'value1'
key at 13 = 'key2'
value at 18 = 'value2'
key at 27 = 'key3'
value at 32 = 'value3'
key at 40 = 'key3.5'
key at 48 = 'key4'
key at 53 = 'key5'
value at 58 = 'value5'
key at 67 = 'GoofyStuff'
value at 78 = 'I like kittens'
key at 95 = 'key6'
key at 100 = 'key7'
key at 105 = 'ForReal-Things'
value at 120 = 'be sure to vote'
key at 138 = 'key8'

总结

  • (?&lt;=^|[\s)\n]*) 查找键的开头,假定每个键位于字符串的开头,或者紧跟在 \n、"(" 或空格之后 - (?&lt;=^|[\s)\n]*)这可能不适用于Java 在处理未定义大小的外观方面存在错误/功能。 (see also)
  • (?&lt;=^|[\s)\n]) 查找键的开头,假定每个键位于字符串的开头,或者紧跟在 \n、"(" 或空格之后 - (?&lt;=^|[\s)\n])。这个样子around 似乎在 C# 和 Powershell 中工作

  • ([^(\n\s]*) 返回直到下一个“(”、\n 或 \s 的所有字符

  • ([(]([^)\n]*)[)])? 如果存在则返回 parans 中的值

    循环内的额外逻辑测试 Matches 数组以验证是否找到了键名或值。在 powershell 中,$Matches 会自动填充字符串中的所有匹配项。

【讨论】:

  • 注意:此解决方案适用于 C#,但目前依赖于 Java 正则表达式实现中的错误/功能。
  • 这是在 powershell 中编写和测试的,您能否扩展您所指的错误/功能?
  • 检查这个问题:stackoverflow.com/questions/1536915/… Java 正则表达式的“官方”文档在 Pattern 类中,它并没有真正详细描述什么被认为是无效的后视。因此,尚不清楚这是错误还是功能。
  • 这是 Java 的一个有趣缺陷。我将通过从环视中删除“*”来更新此答案
  • 没有分析您的正则表达式 - 但是,它不需要 ** 实际上使它等同于空字符串。如果我没记错的话,look-behind 总是尝试匹配最短的字符串。
【解决方案2】:

我的建议是:

Pattern p = Pattern.compile("(\\(?[^ \\n(]+\\)?)+"), Pattern.DOTALL);

然后,遍历子匹配。如果第一个字符是一个括号,你就知道它是前一个键的值;否则,这是一个关键。如果它是一个值,只需使用 substring 去掉括号即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-03
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    • 2013-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多