【问题标题】:Regex - Split string into array based on punctuation/spaces正则表达式 - 根据标点符号/空格将字符串拆分为数组
【发布时间】:2017-10-08 03:09:51
【问题描述】:

我需要一种方法,根据标点符号或空格的存在将字符串分成几个不同的部分。

我的意思是,每个单词都应该被分割成自己的数组元素,而且单词开头或结尾的标点符号也应该放在自己的数组元素中数组元素。

例如: 我需要能够将字符串Hello, Harry Potter. I'm Tom Riddle. 变成

array(
   "Hello",
    ", "
    "Harry",
    "Potter"
    ". ",
    "I'm",
    "Tom",
    "Riddle",
    ". "
)

因此单词中间的标点符号(例如单词中间的撇号)不应造成分隔 **编辑:**为了澄清所需的行为,I'mdidn't 等应保留一个单词,但hello!"okay, 等应与开头或结尾的标点符号分开。

另外,我想在搜索中包含的标点符号是:

  • 。 (句号/句号)
  • ? (问号)
  • ! (感叹号)
  • ,(逗号)
  • ; (分号)
  • :(冒号)
  • (-)(连字符-破折号)
  • ((开始括号)
  • )(结束括号)
  • {(开始花括号)
  • }(结束波浪形大括号)
  • [(开始方括号)
  • ](结束方括号)
  • '(单引号)
  • "(双引号)
  • …(省略号)

我找到的最接近我需要的结果是这样的:

preg_split('/(\s|[\.,\/])/', $string, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

但是,这样做的问题是:

  • 标点中间词算作正常标点
  • 包含数组元素的数组元素也不包含空格。 编辑:抱歉含糊不清;通过这个,我的意思是我希望标点符号包含在标点符号之后/之前的空格。例如如果是逗号,则为,(后面有空格),但如果是左括号,则为((前面有空格)。
  • 当我添加我需要的其余标点符号 (preg_split("/(\s|[\.?!,;:-(){}[]'\"…\/])/",) 时出现错误。我很确定这个错误是由于一个未转义的字符造成的,所以我通过preg_quote 运行了整个事情,它返回了\.\?\!,;\:\-\(\)\{\}\[\]'"…,但这仍然给出了错误:Parse error: syntax error, unexpected '…' (T_STRING), expecting ',' or ')' in [...][...] on line 5

我对正则表达式的理解相当有限,但是在查看 php 文档后,我可以收集到上面的代码在遇到的每个空格处或每次遇到逗号或标点符号时都会分隔单词。 (如果我错了,请纠正我?)据我所知,在方括号内添加其余字符也会使其在任何这些字符处分隔字符串(?)因为这不起作用,我假设我对它的工作原理有某种基本的误解,因此将不胜感激。

【问题讨论】:

    标签: php regex


    【解决方案1】:

    这样就可以了,但是输出略有不同,因为您将 ' 作为要拆分的字符包含在内,因此 I'm 将被拆分:

    $result = preg_split('/(\.\.\.\s?|[-.?!,;:(){}\[\]\'"]\s?)|\s/',
                         $string, null, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
    

    它可能会被简化,但我只是将省略号 ... 与可选空格或所有其他字符包含在可选空格或空格中。

    您需要在字符类[]之外转义点.,在字符类内转义[],并且-需要转义或排在第一位或最后一位,以免来表示一个范围。显然,您需要转义用于包含该模式的引号,在本例中为单个 '

    您没有指定标点符号两侧是否需要空格,并且不清楚这个“标点中间词算作正常标点符号”是否意味着它应该或不应该'数。

    【讨论】:

    • 哈哈 正要问一个问题,但我看到你在 :P 中编辑了它 非常感谢,这很好:) 请问为什么没有办法排除结果介于角色 AZ 之间?当我试图自己解决这个问题时,我认为我也许可以使用^ 来排除此类实例,但我找不到解决方法。我是否误解了否定的工作原理?
    • 编辑最后一段。
    • 抱歉含糊不清;我更新了问题以澄清所需的行为。
    • 嗯...我明白了。还是很模糊,如果(" 是字符串中没有空格的第一个字符呢?
    • 我原本打算让那些没有空格的(只是为了更容易从数组中重新创建字符串),但现在我考虑了一下,我认为它会最好保持标点符号没有任何空格,并在它们之间保留空格(所以会有一个只有空格(` `,) 的数组元素),这可能吗?我应该编辑问题来代替吗?
    【解决方案2】:

    一般你可以使用该模式

    word character+[all your punctuation characters here]+word character(*SKIP)(*FAIL)
    

    例如:

    \w[\[\].?\"\']\w(*SKIP)(*FAIL)|[\[\].?\"\']
    

    a demo on regex101.com

    【讨论】:

      【解决方案3】:

      您真的希望 all 单词内部标点保持连接吗?此外,您似乎想分别标记每个标点符号(但附加附近的空格),这是大部分工作。如果你真的这样做,这应该这样做。附带一个测试字符串以在工作中显示它。

      $string = "Hello, it's me-me-it's-me!!! o... (a friend?)";
      print_r( preg_split("/(\w\S+\w)|(\w+)|(\s*\.{3}\s*)|(\s*[^\w\s]\s*)|\s+/", $string, 
              -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE) );
      

      输出:

      Array
      (
          [0] => Hello
          [1] => ,
          [2] => it's
          [3] => me-me-it's-me
          [4] => !
          [5] => !
          [6] => !
          [7] => o
          [8] => ... 
          [9] => (
          [10] => a
          [11] => friend
          [12] => ?
          [13] => )
      )
      

      这就是它的工作原理:

      1. (\w\S+\w) 捕获任何超过 3 个字符的单词,允许嵌入非字母。
      2. (\w+) 捕捉任何单词(捕捉短词)。
      3. (\s*\.{3}\s*) 捕获省略号...,以及周围的任何空间。
      4. (\s*[^\w\s]\s*) 单独捕获任何非字母、非空格字符;但附加任何附近的空间。
      5. \s+ 任何其他空格(即单词之间)分割字符串,但没有被捕获。

      如果您想对单词中的内容有所选择,请将第一个备选方案中的 \S+ 替换为您希望允许的内容列表,例如,[\w'-]+ 仅允许撇号和连字符。

      【讨论】:

      • 非常感谢您的回复;您在第 4 项中描述的内容似乎不起作用,或者您可能误解了我的问题(如果措辞不当,请道歉)。 gyazo.com/2db04904b5f9a5c9d06a7986c507b057 我的预期结果是逗号后面有一个空格,所以 2 将是 ", "。如果这不可能,那么是否可以让空格也返回数组中,以便我可以循环遍历它并像那样操作它?
      • 实际上忽略最后一条评论,查看我的代码,我认为将空格作为它们自己的元素会更容易(所以会有一个数组元素只包含一个空格) .是否可以更改代码来做到这一点?
      • 糟糕,如果我也使用了var_dump(),我就会发现错误。事实上,这应该用逗号来捕捉空间,但还不确定我做错了什么。但我希望你能看到这种方法是如何工作的,并能够将它调整到你真正想要的任何东西(这仍然不完全清楚,尽管你的 - 原始 - 需求的这方面是)。
      • 当然可以更改要求。但是请注意,当您这样做时,SO 人(以及所有程序员)会有些恼火。下次您无法避免提出“解决我的混乱问题”的问题时,请尽一切努力从一开始就准确地说明您需要什么。那么现在您希望 all 空格作为单独的标记返回,还是仍然希望单词之间的空格被丢弃(这是一种疯狂的标记方式)?
      • 抱歉回复晚了; SO 应用程序已退出,所以我没有收到通知 >.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-14
      • 1970-01-01
      • 1970-01-01
      • 2016-12-03
      • 1970-01-01
      • 2013-11-22
      相关资源
      最近更新 更多