Php 正则表达式用于过滤具有挑战性的字符串,包括破折号、空格、数字和某些单词

Php 正则表达式用于过滤具有挑战性的字符串,包括破折号、空格、数字和某些单词,php,regex,preg-replace,Php,Regex,Preg Replace,对于我的搜索面板,我必须过滤一个如下所示的刺: '4dan-7kyu' or '4dan - 7kyu' or '10kyu' or '10 kyu' or '2dan' or '2 dan' or '4-7' or '4 - 7' or '10' 只允许: 编号从1-10 不区分大小写的单词包括:dan,kyu,ааа,аа 破折号(不超过一个且从不在字符串开头,从不-10kyu或从不-10) 空格(不超过一次,但绝不在字符串开头) 我曾想过这样的事情,但从来没有对我完全起作用:

对于我的搜索面板,我必须过滤一个如下所示的刺:

'4dan-7kyu' or '4dan - 7kyu' or '10kyu' or '10 kyu' or '2dan' or '2 dan' or  '4-7'  or '4 - 7'  or  '10'  
只允许:
  • 编号从
    1-10
  • 不区分大小写的单词包括:
    dan
    kyu
    ааа
    аа
  • 破折号(不超过一个且从不在字符串开头,从不
    -10kyu
    或从不
    -10
  • 空格(不超过一次,但绝不在字符串开头) 我曾想过这样的事情,但从来没有对我完全起作用:

    /([1-9]| 10)\s-\s|dan|kyu|||||||||/i

    编写这种正则表达式的正确方法是什么

    编辑1:

  • 空格(不超过一次,但绝不在字符串开头)
    无效示例:
    4dan\uuuuuuu-\uuuuuu 7kyu
    \u4dan\uuuu7kyu

    有效示例:
    4dan-7kyu
    4dan-7kyu
    4 dan-7kyu
    4 dan-7kyu
  • 编辑2:

    更多无效示例:
    12dan-7kyu
    12dan-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
    

    向武术同仁致意

    如果我很了解您的要求,您可以尝试以下正则表达式:

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

    开头的负向前看确保字符串中没有两个或更多空格或破折号

    然后,在匹配组中使用可能的组合,并捕获所有内容以获得不带引号的字符串。您还可以使用“向前看”和“向后看”来避免捕获

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

    您只需对正则表达式稍加修改即可:

    /((10|[1-9])(\s?-?\s?)(dan|kyu|дан|кью)?(\s?-?\s?)(([10|[1-9])(\s?-?\s?)(dan|kyu|дан|кью)?)?)/i
    
    这将使用原始正则表达式,但使数字和dan或kyu之间的空格和连字符可选,然后有另一个可选的空格和连字符,然后可选地重复

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

    \b(?<!-)(10|[1-9])(?: ?(dan|kyu|дан|кью))?(?: ?- ?(10|[1-9])(?: ?(dan|kyu|дан|кью))?)?\b
    

    当然,按照你自己的规则
    4-7
    是无效的(规则4)?我猜他的意思是你不应该让两个空格字符相邻。但是
    \s-\s
    应该还可以。请添加一些有效和无效字符串的示例。Jerry,非常好,但是匹配
    4dan-7kyu
    并且不带引号(只是示例)@IliaRostovtsev是整个字符串
    4dan-7kyu
    ?如果是这样,您可以完全删除引号并使用锚定,方法是将
    ^
    放在开头,将
    $
    放在结尾。此外,此字符串将不匹配,因为其中有2个空格。@IliaRostovtsev Awesome!:D@IliaRostovtsev没关系,我不得不早点离开去吃午饭,在这段时间里看不到你的评论,所以这很公平。:)我在您的示例中发现了另一个错误:D.如果您键入
    11dan-11kyu
    ,那么它就可以了,但是如果您去键入
    10dan-11kyu
    ,那么它就可以在不允许的情况下继续执行;)有趣的示例,但如果您输入
    $rgData=['12','20dan']这没有什么区别,你的例子让它通过,当它不应该@IliaRostovtsev-是的,没有提到
    ^
    $
    。更具体地说,增加了不同的案例。谢谢。好多了,谢谢!!但是它不允许有效的条目,即
    1kyu-4kyu
    1kyu-4kyu
    。你能把它修好让它也匹配吗?还有,如果可能的话,不要删除
    \u 1kyu-4kyu
    只要把它放在那里,但格式化成
    1kyu-4kyu
    @IliaRostovtsev这是一种秘密的dzen regex技术:哇!我对阿尔玛说的话你说得对!太棒了,哦!!工作100%精确!!哦,你的例子真是太美了!谢谢你们所有人,谢谢你们的精彩回答!!如果可以的话,我会接受你所有的3个答案,但由于阿尔玛是第一个提供真正有效示例的人,我将不得不接受阿尔玛的答案!
    $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);