Сопоставлять инициалы из строки имени, игнорируя заголовки, используя Regex - PullRequest
3 голосов
/ 30 апреля 2020

Я пытаюсь получить инициалы строки имени, но строка может содержать заголовок, который я хочу игнорировать, и иметь несколько или одно имя. Как я могу сделать это только с помощью Regex в Javascript?

Я могу сопоставить первый символ слов в строке с \b(\w), но я хочу игнорировать 'Mr' и 'Mrs' et c. Нечто подобное .. [^mr]\b(\w), но это поднимает M в mr и пробеле впереди и не игнорирует другие заголовки

Примеры строк и совпадений:

'Mr Bob Smith' -> BS
'Miss Jessica Blue' -> JB
'tim white' -> TW
'dr Lisa S pink' -> LS
'lord Lee Kensington-Smithe' -> LK

Ответы [ 5 ]

0 голосов
/ 30 апреля 2020

вот более javascript ориентированный подход:

var initials = fullNames.map(fullname => {
    return fullname
        .replace(/^(?:Mr|Miss|dr|lord)\.? ?/, '') // remove title
        .split(' ')
        .map(substring => substring[0].toUpperCase())
        .join('')
        .substring(0, 2) // this part is to match only 2 chars
});
// => [ 'BS', 'JB', 'TW', 'LS', 'LK' ]

Вы можете удалить часть .substring(0, 2), если у вас все в порядке с 'dr Lisa S pink' === LSP

const fullNames = [
    "Mr Bob Smith",
    "Miss Jessica Blue",
    "tim white",
    "dr Lisa S pink",
    "lord Lee Kensington-Smithe"
]

const initials = fullNames.map(fullname => {
    return fullname
        .replace(/^(?:Mr|Miss|dr|lord)\.? ?/, '')
        .split(' ')
        .map(substring => substring[0].toUpperCase())
        .join('')
        .substring(0, 2)
})
const initialsV2 = fullNames.map(fullname => {
    return fullname
        .replace(/^(?:Mr|Miss|dr|lord)\.? ?/, '')
        .split(' ')
        .map(substring => substring[0].toUpperCase())
        .join('')
})
$('#initials').html(fullNames.map( (fullName, i) => `${fullName.padEnd(28, ' ')} => ${initials[i]}` ).join('\n'))

$('#initials2').html(fullNames.map( (fullName, i) => `${fullName.padEnd(28, ' ')} => ${initialsV2[i]}` ).join('\n'))


V1 only 2 letters

V2 any letters length

0 голосов
/ 30 апреля 2020

Я предпочитаю несколько шагов вместо сложных для анализа регулярных выражений.

# Ignore case
name = "Mr. Frank Smith".lower()

# Get rid of the title 
name = re.sub("^(lord|mrs|mr)[.]? ","", name)

# get each first letter
name_list = name.split(" ")
for n in name_list:
    # might need to exclude III, Jr. etc.
    initials += n[0].upper()

Из ваших примеров не ясно, хотите ли вы также отчество или просто первые два имени. В зависимости от того, что вы хотите, вы можете, например, использовать следующую строку вместо для l oop:

# only first and second name, even if exclude last name
initials = name_list[0][0].upper() + name_list[1][0].upper()
0 голосов
/ 30 апреля 2020

Это работает для меня

(\w)\w+ (\w)\w+$
0 голосов
/ 30 апреля 2020

Если приемлем LSP и вариант заголовков в верхнем и нижнем регистре, вы можете использовать

let pattern = /\b(?:(?:Mr|Miss|dr|lord)? )?(\w+(?:[ -]\w+)*)\b/i;

Regex demo

let pattern = /\b(?:(?:Mr|Miss|dr|lord)? )?(\w+(?:[ -]\w+)*)\b/i;
let strings = [
  "Mr Bob Smith",
  "Miss Jessica Blue",
  "tim white",
  "dr Lisa S pink",
  "lord Lee Kensington-Smithe"
];

strings.forEach(s => {
  let m = s.match(pattern);

  if (m) {
    console.log(m[1].split(" ").map(s => s.charAt(0).toUpperCase()).join(""));
  }
});

Если вы хотите сопоставить только строчные или прописные буквы для имен, вы можете использовать чередование. Для названий вы также можете использовать чередование, которое может быть необязательным.

\b(?:(?:Mr|Miss|dr|lord)? )?((?:[A-Z]\w*(?:[ -][A-Z]\w*)*|[a-z]+(?: [a-z]+)))\b

По частям

  • \b Граница слова
  • (?: Без захвата группа
    • (?:Mr|Miss|dr|lord)? Соответствует любой из альтернатив
  • )? Закрыть группу и сделать ее необязательной
  • ( Захват группа 1
    • (?: Группа без захвата
      • [A-Z]\w*(?:[ -][A-Z]\w*)* Совпадение частей, начинающихся с заглавной буквы
      • | Или
      • [a-z]+(?: [a-z]+) Подбирать только строчные буквы
    • ) Закрыть группу
  • ) Закрыть группу
  • \b Граница слова

Regex demo

let pattern = /\b(?:(?:Mr|Miss|dr|lord)? )?((?:[A-Z]\w*(?:[ -][A-Z]\w*)*|[a-z]+(?: [a-z]+)))\b/;
let strings = [
  "Mr Bob Smith",
  "Miss Jessica Blue",
  "tim white",
  "dr Lisa S pink",
  "lord Lee Kensington-Smithe"
];

strings.forEach(s => {
  let m = s.match(pattern);

  if (m) {
    console.log(m[1].split(" ").map(s => s.charAt(0).toUpperCase()).join(""));
  }
});
0 голосов
/ 30 апреля 2020

Я могу решить эту проблему, используя отрицательный взгляд вперед и позитивный взгляд позади. Вы можете попробовать это:

function firstChars(str) {
	const regex = /(?!\bmr\.?\b|\bmiss\b|\blord\b|\bdr\b)((?<=\s)|(?<=^))(\b[a-z])/ig;
	const matches = [...str.match(regex)];
	
	return matches.map(char => char.toUpperCase()).join('');
}

console.log(firstChars('Mr Bob Smith'));
console.log(firstChars('Miss Jessica Blue'));
console.log(firstChars('tim white'));
console.log(firstChars('dr Lisa S pink'));
console.log(firstChars('Drone Picker'));
console.log(firstChars('lord Lee Kensington-Smithe'));
.as-console-wrapper{min-height: 100%!important; top: 0}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...