Regex过滤具有挑战性的字符串,包括破折号、空格、数字和某些单词


Regex to filter challenging string, having a dash, spaces, numbers and certain words

对于我的搜索面板,我必须过滤一个看起来像的刺痛

'4dan-7kyu' or '4dan - 7kyu' or '10kyu' or '10 kyu' or '2dan' or '2 dan' or  '4-7'  or '4 - 7'  or  '10'  

只允许:

  1. 1-10中的数字
  2. 不区分大小写的单词包括:dankyuданкью
  3. 短划线(不超过一个AND,从不在字符串开头,从不-10kyu或从不-10
  4. 空格(不超过一次,但从不在字符串开头)

我曾想过这样的事情,但它从未完全适用于我:

/([1-9]|10)'s-'s|dan|kyu|дан|кью/i

什么是正确的方式来榨干这样的Regex?

编辑1:

  1. 空格(不超过一次,但从不在字符串开头)
    无效示例:4dan___-___7kyu_4dan_-_7kyu
    有效示例:4dan-7kyu4dan - 7kyu以及4 dan - 7kyu4 dan - 7 kyu

编辑2:

更多无效示例:12dan-7kyu12dan-11kyu

我想那是:

/(^([1-9]|10)'s*$)
|
(^([1-9]|10)'s?-'s?([1-9]|10)'s*$)
|
(^([1-9]|10)'s?(dan|kyu|дан|кью)'s*$)
|
(^([1-9]|10)'s?(dan|kyu|дан|кью)'s?-'s?([1-9]|10)'s?(dan|kyu|дан|кью)'s*$)/ixu

以下是PHP示例:

$rgData   = ['12', '20dan', ' 1kyu - 4kyu   ', '1kyu - 4kyu  ', 
             '1 kyu - 4 kyu', '1 kyu-4 kyu','4dan-7kyu', '4dan - 7kyu', 
             '10kyu', '10 kyu', '2dan', '2 dan', '4-7', '4 - 7', '10'];
$sPattern = '/(^([1-9]|10)'s*$)
             |
             (^([1-9]|10)'s?-'s?([1-9]|10)'s*$)
             |
             (^([1-9]|10)'s?(dan|kyu|дан|кью)'s*$)
             |
             (^([1-9]|10)'s?(dan|kyu|дан|кью)'s?-'s?([1-9]|10)'s?(dan|kyu|дан|кью)'s*$)/ixu';
var_dump(array_filter($rgData, function($sItem) use ($sPattern)
{
   return preg_match($sPattern, $sItem, $rgMatches);
}));//first 3 not matched

附言:问候武术同事!

如果我很了解您的需求,您可以尝试以下regex:

'((?!(?:[^''s]*'s[^''s]*){2,}'|(?:[^'-]*-[^'-]*){2,}')(?:(?:[1-9]|10)'s?-?(?:dan|kyu|дан|кью)?-?)*)'

查看regex101 上的演示

开头的负先行检查确保字符串中没有两个或多个空格或破折号。

然后,只需在匹配组中有可能的组合,并捕获所有内容即可获得不带引号的字符串。您也可以使用先行和后向来避免捕获。

(?<=')(?!(?:[^''s]*'s[^''s]*){2,}'|(?:[^'-]*-[^'-]*){2,}')(?:(?:[1-9]|10)'s?-?(?:dan|kyu|дан|кью)?-?)*(?=')

编辑:

根据更新,您也许可以尝试以下regex:

^(?:(?:[1-9]|10)(?![0-9])) ?(?:(?:dan|kyu|дан|кью) ?)?(?:-? ?(?:(?:[1-9]|10)(?![0-9])) ?(?:(?:dan|kyu|дан|кью) ?)?)*$
'b(?<!-)(10|[1-9])(?: ?(dan|kyu|дан|кью))?(?: ?- ?(10|[1-9])(?: ?(dan|kyu|дан|кью))?)?'b

查看捕获

我创建了上面的regex,但它不太可读,所以如果你把它放在代码中,你可以让"下一个家伙"更容易理解它(我注意到你有preg-replace作为标签,所以我假设是PHP):

$numbers = '(10|[1-9])';
$words = '(dan|kyu|дан|кью)';
$seperators = ' ?- ?';
$regex =
  '~'b'.
    '(?<!-)'.
    $numbers.
    '(?:'.
      ' ?'.
      $words.
    ')?'.
    '(?:'.
      $seperators.
      $numbers.
      '(?:'.
        ' ?'.
        $words.
      ')?'.
    ')?'.
  ''b~';
$string = "'12dan-7kyu' or '12dan-11kyu' or '_4dan_-_7kyu' or '4 dan - 7kyu' or '4 dan - 7 kyu' or '4dan___-___7kyu' or '4dan-7kyu' or '4dan - 7kyu' or '10kyu' or '10 kyu' or '2dan' or '2 dan' or  '4-7'  or '4 - 7'  or  '10'  ";
preg_match_all($regex, $string, $out, PREG_SET_ORDER);

看它跑

您只需要在RegEx中稍作修改即可:

/((10|[1-9])('s?-?'s?)(dan|kyu|дан|кью)?('s?-?'s?)(([10|[1-9])('s?-?'s?)(dan|kyu|дан|кью)?)?)/i

这使用了原始的RegEx,但在数字和dan或kyu之间的空格和连字符是可选的,然后又有很多可选的空格和连字符,然后可选地重复。

我还交换了[1-9]|10部分,以阻止它抓住1并继续前进。