2

对于我的搜索面板,我必须过滤如下所示的字符串:

'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. 不区分大小写的单词包括:dan, kyu, дан, кью;
  3. 破折号(不超过一个并且从不在字符串的开头,从不-10kyu或从不-10);
  4. 空格(不超过一次,但从不在字符串的开头);

我正在考虑这样的事情,但它从未对我完全有效:

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

拧这种正则表达式的正确方法是什么?

编辑1:

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

编辑2:

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

4

4 回答 4

4

我猜是:

/(^([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

PS向武术同事问好!

于 2013-08-28T07:55:30.870 回答
4

如果我很好地理解了你的要求,你可以试试这个正则表达式:

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

请参阅 regex101 上的演示

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

然后,只需在匹配组中拥有可能的组合,并捕获所有内容以获取不带引号的字符串。您还可以使用前瞻和后瞻来避免捕获。

(?<=')(?!(?:[^'\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|дан|кью) ?)?)*$
于 2013-08-28T08:02:15.200 回答
4
\b(?<!-)(10|[1-9])(?: ?(dan|kyu|дан|кью))?(?: ?- ?(10|[1-9])(?: ?(dan|kyu|дан|кью))?)?\b

查看捕获。

我创建了上面的正则表达式,但它不太可读,所以如果你把它放到代码中,你可以让“下一个人”更容易理解(我注意到你有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);

看它运行。

于 2013-08-28T09:01:57.557 回答
0

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

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

这使用您原来的正则表达式,但使空格和连字符在数字和 dan 或 kyu 之间是可选的,然后有另外很多可选的空格和连字符,然后可以选择重复。

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

于 2013-08-28T08:03:40.447 回答