RegEx для проверки строк с несколькими буквенно-цифровыми образцами - PullRequest
1 голос
/ 03 июня 2019

Я делаю бота и хочу, чтобы бот отслеживал групповые расходы.Мне нужно иметь возможность сообщить боту о сумме, которая была заплачена, и об участниках (то есть список людей, за которых заплатил пользователь, который печатает ввод).Участник должен представлять собой последовательности из двух букв, взятых из латинского алфавита в верхнем регистре (цифры или другие символы не допускаются).

ПРИМЕР: Скажите, что я иду на обед с моими друзьями FH, GT, YU, WQ иCS.Чтобы рассказать боту о нашем совместном обеде, я напишу общую сумму, которая была выплачена, затем '|', а затем соответствующие люди, которые приняли участие в мероприятии, кроме меня (таким как FH, GT, YU, WQ,CS).Если я хочу (но это не обязательно), я могу также поставить пробел после списка имен и написать имя события: если оно присутствует, имя события всегда должно быть заключено в двойные кавычки (").

Например, это допустимый ввод:

 65|FH,GT,YU,WQ,CS "lunch out"

Таким образом, формат: число, |, имена (разделенные запятыми), пробел, имя события (последние дванеобязательно).

Число всегда должно быть положительным (по очевидным причинам) и может быть целым числом (например, 65) или десятичным (например, 65,7, 65,32 и т. д.). Если число является десятичным числом,он может содержать не более 2 цифр после десятичной точки.

Все они также являются допустимыми значениями:

65|FH,GT,YU,WQ,CS 
34.56|FH,GT "club night"
120.7|FH,GT,KM,LW,AS,XZ,PO "cinema tickets"

Один и тот же участник не может быть упомянут более одного раза, поэтому следующееввод недействителен.

65|FH,GT,YU,WQ,CS,GT

Вкратце: команда должна начинаться с суммы, за которой следует разделитель |, за которым следует список людей, за которых заплатил пользователь. Необязательно вставлять сообщение, описывающеерасход.

Есть бесконечно много входов, которые действительныВсе они будут разными, но все будут следовать приведенным выше правилам (ни один участник не упоминается дважды, каждый участник разделяется запятой, сумма представляет собой целое число или десятичное число, не более 2 цифр после десятичной точки и т. Д.).).

Однако я не могу «захватить» то, что они все разделяют (их «формат» соответствует правилам, которые я изложил), чтобы бот мог отличить действительные входные данные от недействительных.Я думал об использовании регулярного выражения.Я не очень знаком с регулярными выражениями, но мне кажется, что регулярное выражение не может охватить все возможные формы ввода (например, количество имен, количество десятичных цифр в количестве, необязательное имя длясобытие и так далее)

Как мне поступить?

Ответы [ 2 ]

1 голос
/ 03 июня 2019

Возможно, можно обработать дубликат с помощью регулярных выражений, но для упрощения я буду использовать split и цикл вместо

var txt = `65|FH,GT,YU,WQ,CS
34.56|FH,GT "club night"
65|FH,GT,YU,WQ,CS,GT "this is not valid"
65|AH,GT,YU,AH
120.7|FH,GT,KM,LW,AS,XZ,PO "cinema tickets"`

var lines = {
  valid: [],
  notValid: []
};

txt.split("\n").forEach(line => {
  var isValid = true,
    persons = [],
    l = line.trim().replace(/.*\|([\w,]+)(\s".*)?/, "$1")

  l.split(/[,\s]/).forEach(p => {
    if (persons.includes(p))
      isValid = false;
    persons.push(p)
  })

  if (isValid)
    lines.valid.push(line)
  else
    lines.notValid.push(line)
})

console.log(lines)
0 голосов
/ 03 июня 2019

Это выражение довольно интересное.Мы подошли бы к этой проблеме с имеющимися у нас шаблонами, которые включают числа, за которыми следует труба:

(\d+(\.\d+)?)\|

нежелательные повторяющиеся две буквы:

(([A-Z]{2}),?).*?(\1)

желаемые повторяющиеся двабуквы:

(([A-Z]{2}),?)

необязательные слова в кавычках:

\s+"[\w\s]+"

, и мы можем использовать изменение:

(\d+(\.\d+)?)\||(([A-Z]{2}),?).*?(\1)|(([A-Z]{2}),?)|\s+"[\w\s]+"

всякий раз, когда вторая часть не undefined, тогда эта строка недопустима, в противном случае допустима, и мы будем писать остальную часть проблемы.

Демо

Тест

const regex = /(\d+(\.\d+)?)\||(([A-Z]{2}),?).*?(\1)|(([A-Z]{2}),?)|\s+"[\w\s]+"/gm;
const str = `65|FH,GT,YU,WQ,CS 
34.56|FH,GT "club night"
120.7|FH,GT,KM,LW,AS,XZ,PO "cinema tickets"

65|FH,GT,YU,WQ,CS,GT`;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

Схема RegEx

jex.im визуализирует регулярные выражения:

enter image description here

...