正则表达式范围问题

时间:2019-02-28 12:11:13

标签: php regex

我正在尝试制作一个验证以下格式的正则表达式:

  • 只有数字以或-分隔。
  • 可能存在数字范围(以-分隔)
  • 数字应该从1到31
  • 第二个部分的值在一个范围内大于第一个部分(这比较复杂,但是如果非常困难,我将其丢弃)

我认为有效的示例:

4,31,2-22,8
29,1-10,2-12,9

我认为无效的示例:

4,31,2-22,8,
29,1-10,-2-12-,9
29,1-50,12-2,32

到目前为止,我的正则表达式如下:

yourDictionnary = open('Dictionary.txt', 'r').read().splitlines() #this puts contents from the dictionnary into a list line by line
theCsvContent = ','.join(open('csvName.csv', 'r').read().splitlines()).split(',') #this puts contents from the csv into a list element by element

for index, word in enumerate(theCsvContent): #loops through theCsv with index as the word index and word as the word we're iterating on
    if word not in yourDictionnary: #checks if the word is in dictionnary and if not :
        del theCsvContent[index] #removes the word from the csv

open('result.csv', 'w').write(','.join(theCsvContent)) #this writes the edited csv into result.csv

此表达式此刻使我很好地理解了“-”和“,”,并且数字从1到31。排名问题是第二个值大于第一个值,我不知道如何解决它。 有什么建议吗?

2 个答案:

答案 0 :(得分:1)

正如Jeff已经建议的那样,我不会使用正则表达式,因为它很难理解。

解决方案比看起来简单得多:

function isValid($string)
{
    $numbers = explode(',', $string);

    // Covers the case when you have an empty value at the beginning/end of string.
    if (count($numbers) !== count(array_filter($numbers))) {
        return false; 
    }

    foreach ($numbers as $number) {
        if (is_numeric($number) && $number >= 1 && $number <= 31) {
            continue;
        }

        if (!preg_match('/^(\d+)-(\d+)$/', $number, $matches)) {
            return false;
        }

        if ($matches[1] >= 1 && $matches[1] <= 31 && 
            $matches[2] >= 1 && $matches[2] <= 31 && 
            $matches[2] > $matches[1]
        ) {
            continue;
        }

        return false;
    }

    return true;
}

$strings = [
    '4,31,2-22,8',
    '29,1-10,2-12,9',
    '4,31,2-22,8,',
    '29,1-10,-2-12-,9',
    '29,1-50,12-2,32',
];


foreach ($strings as $string) {
    var_dump(isValid($string));
}

结果将是:

bool(true)
bool(true)
bool(false)
bool(false)
bool(false)

答案 1 :(得分:1)

我认为最好将正则表达式和常规代码结合使用。此函数检查整个字符串是否匹配以逗号分隔的数字或范围的模式,然后提取单个数字或范围,并对它们应用其他错误检查(在1到31之间,结束> =开头):

function validate_range($range) {
    if (!preg_match('/^((\d+(?:-\d+)?)(?:,(?!$)|$))+$/', $range)) return false;
    preg_match_all('/(\d+(?:-\d+)?)/', $range, $matches);
    foreach ($matches[1] as $match) {
        if (strpos($match, '-') !== false) {
            list($start, $end) = explode('-', $match);
            if ($end < $start) return false;
            if ($start < 1 || $start > 31 || $end < 1 || $end > 31) return false;
        }
        if ($match < 1 || $match > 31) return false;
    }
    return true;
}

您可以像这样测试它:

$ranges = array(
    '4,31,2-22,8',
'29,1-10,2-12,9',
'4,31,2-22,8,',
'29,1-10,-2-12-,9',
'29,1-50,12-2,32');
foreach ($ranges as $range) {
    if (validate_range($range)) 
        echo "$range is OK!\n";
    else
        echo "$range is no good\n";
}

输出:

4,31,2-22,8 is OK!
29,1-10,2-12,9 is OK! 
4,31,2-22,8, is no good 
29,1-10,-2-12-,9 is no good 
29,1-50,12-2,32 is no good

Demo on 3v4l.org

相关问题