除了括号内的数字和部分字符外,删除所有内容。

3

想要删除除了 # NewLine、完成的括号集合和大括号内的数字之外的所有内容。
示例输入:

# (1296) {20} [529] [1496] [411]
# (MONDAY ) (1296)
# (646) {20} (BEACH 7) [20 Mtrs] { 03 Foot }
# {19} [455] [721] (1296) (SUNDAY ) [2741] (MONDAY (WEDNESDAY {20}
# {19} (1296)

不起作用的代码:

$re = '/(?:\[[^][]*]|\([^()]*\)|{[^{}]*})(*SKIP)(*F)|[^][(){}@#]+/m';
$result = preg_replace($re, '', $input);

输出结果不正确:

#(1296){20}[529][1496][411]
#(1296) 
#(646){20}(BEACH 7)[20 Mtrs]{ 03 Foot }
#{19}[455][721](1296)[2741](({20}
#{19}(1296)

期望的输出:

#(1296) {20} [529] [1496] [411]
#(1296)
#(646) {20}
#{19} [455] [721] (1296) [2741] {20}
#{19} (1296)

当我看到类似 (MONDAY (WEDNESDAY {20} 这样的东西时,我几乎想使用换行符和空格对其进行标记化,并检查每个标记。 - Chris Haas
1
请查看此PHP演示 - Wiktor Stribiżew
1
一个想法,替换正则表达式 ((?:\[\d*\]|\(\d*\)|{\d*})\s?)|[^#\r\n]$1 - bobble bubble
3个回答

5
你可以在括号内匹配至少1个数字,然后跳过该匹配。
然后匹配除换行符或#之外的任何字符,并将其替换为空字符串。
(?:\[\h*\d[\h\d]*]|\(\h*\d[\h\d]*\)|{\h*\d[\h\d]*})\h*(*SKIP)(*F)|[^#\n]

解释

  • (?: 非捕获组
    • \[\h*\d[\h\d]*] 匹配方括号中至少1个数字,其中\h匹配水平空格字符(无换行符)
    • |
    • \(\h*\d[\h\d]*\) 括号中的1个数字
    • |
    • {\h*\d[\h\d]*} 大括号中的1个数字
  • )\h* 关闭非捕获组并匹配1个或多个空格
  • (*SKIP)(*F) 跳过并失败匹配(以使其在输出中保持不变)
  • |
  • [^#\n] 匹配除#或换行符之外的任何字符

正则表达式演示


3

您可以使用该正则表达式进行匹配:

(?>(\()|({)|\[)\h*\d[\h\d]*+(?(1)\)|(?(2)}|]))\h*(*SKIP)(*F)|[][(){}]|[^][(){}\r\n#]+

并用空字符串替换。

正则表达式演示

正则表达式详情:

(?>             # Start atomic group
   (\()         # Match ( and capture in group #1
   |            # OR
   ({)          # Match { and capture in group #2
   |            # OR
   \[           # Match [
)               # End atomic group
\h*\d           # Match a digit after 0 or more whitespaces
[\h\d]*+        # Match 0 or more digits or whitespaces
(?(1)           # Condition if capture group 1 is present
   \)           # Match closing )
   |            # Else
   (?(2)        # Condition if capture group 2 is present
      }         # Match closing }
      |         # Else
      ]         # Match closing ]
   )            # End condition of capture group 2
)               # End condition of capture group 1
\h*             # Match 0 or more whitespaces
(*SKIP)(*F)     # Skip and Fail this match that we want to keep
|               # OR
[][(){}]        # Match any of the brackets
|               # OR
[^][(){}\r\n#]+ # Match 1+ of any char not listed inside the [...]

此输入失败 # (1296) {20} [529] [1496] [411] [zz (12) {{45} [星期一] - www.friend0.in
好的,我猜规则对我来说不是很清楚。在行中除了起始位置之外,#还可以出现在其他地方吗?(12可以在第一行,而34)可以在第二行吗? - anubhava
1
#始终位于起始位置,括号必须在同一行中关闭,否则将被视为无效。 - www.friend0.in
1
好的,我明白了,答案已经相应地进行了编辑。 - anubhava
1
完美无瑕! - www.friend0.in

1

您可以使用

<?php

$s = "# (1296) {20} [529] [1496] [411]\n# (MONDAY ) (1296)\n# (646) {20} (BEACH 7) [20 Mtrs] { 03 Foot }\n# {19} [455] [721] (1296) (SUNDAY ) [2741] (MONDAY (WEDNESDAY {20}\n# {19} (1296)";
if (preg_match_all('~^#|(?:(\[)|(\()|{)\d+(?(1)]|(?(2)\)|}))~m', $s, $m)) {
  echo preg_replace_callback('~^(#)\s*|#\s*~', function($m) { return isset($m[1]) ? "#" : "\n#"; }, implode(" ", $m[0]));
}

请查看此PHP演示。输出:

#(1296) {20} [529] [1496] [411] 
#(1296) 
#(646) {20} 
#{19} [455] [721] (1296) [2741] {20} 
#{19} (1296)

详情:

  • ^#|(?:(\[)|(\()|({))\d+(?(1)]|(?(2)\)|})) 可以提取行首的 #,以及在 ()[]{} 括号内的一个或多个数字序列。
  • implode(" ", $m[0]) - 将找到的匹配项用空格连接成一个字符串。
  • preg_replace_callback('~^(#)\s*|#\s*~', function($m) { return isset($m[1]) ? "#" : "\n#"; } - 将字符串开头的 # 和空白替换为单独的 #,将其他所有的 # 替换为它们后面的空格和换行符 + #

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