Perl regex: как получить ту же самую часть - PullRequest
2 голосов
/ 21 февраля 2009

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

chelsea | gordon 
chelsea | jim
chelsea | brad

OR ...

CLANTAG|> jenna
CLANTAG|> jackson
CLANTAG|> irene 

Итак, что я хочу: я хочу захватить КЛАНТАГ, который находится в том же месте и одинаков для каждого имени игрока в этой команде. Но разделителем может быть что угодно - от пустого пространства до нуля (игрок клана1, игрок клана2 ИЛИ игрок клана1, игрок клана2).

Есть идеи, как это сделать?

Заранее спасибо.

Ответы [ 4 ]

4 голосов
/ 21 февраля 2009

Вот выстрел:

use strict;
use warnings;

my($strip) = shift || 0;

print FindTeamName("TEAMJimBob", "TEAMJoeBob", "TEAMBillyBob"), "\n";
print FindTeamName("TEAM|JimBob", "TEAM|JoeBob", "TEAM|BillyBob"), "\n";
print FindTeamName("TEAM | JimBob", "TEAM | JoeBob", "TEAM | BillyBob"), "\n";
print FindTeamName("TEAMJimBob", "TEAM|JoeBob", "TEAM - BillyBob"), "\n";

sub FindTeamName
{
    my(@players) = @_;

    my($team) = shift;
    foreach my $player (@players) {
        $team = FindCommonString($team, $player);
    }

    $team =~ s{\W+$}{} if $strip;

    $team;
}

sub FindCommonString
{
    my($str1, $str2) = @_;

    my(@arr1) = split(//, $str1);
    my(@arr2) = split(//, $str2);

    my($common) = "";

    while (@arr1 && @arr2) {
        my($letter1) = shift(@arr1);
        my($letter2) = shift(@arr2);

        if ($letter1 eq $letter2) {
            $common .= $letter1;
        }
        else {
            last;
        }
    }

    $common;
}

, что дает следующее:

C:\temp>perl test.pl
TEAM
TEAM|
TEAM |
TEAM

C:\temp>perl test.pl 1
TEAM
TEAM
TEAM
TEAM

C:\temp>
1 голос
/ 21 февраля 2009

Редактировать: перечитать вопрос и комментарии ..

Это работает для примера, но может не работать для имен с пробелами или пунктуацией, и, возможно, других сценариев:

while ( <DATA> )
{
    if ( /(\w+).*?(\w+)$/ )
    {
        print "$1, $2\n";
    }
}


__DATA__
team1 | foo
team1 | bar

[another] . user
[another] . player

more-james
more-brown

Дает:

team1, foo
team1, bar
another, user
another, player
more, james
more, brown
1 голос
/ 21 февраля 2009

Принимая дикий удар здесь, это то, что вы хотите?

#! /usr/bin/perl

use strict;
use warnings;

while (<DATA>)
{
  if (/^(\w+) \| (\w+)$/     ||
      /^\[(\w+)\] \. (\w+)$/ ||
      /^(\w+)-(\w+)$/)
  {
    print "tag=$1, name=$2\n";
  }
}

exit 0;

__DATA__
team1 | foo
team1 | bar

[another] . user
[another] . player

more-james
more-brown

Потому что он генерирует:

tag=team1, name=foo
tag=team1, name=bar
tag=another, name=user
tag=another, name=player
tag=more, name=james
tag=more, name=brown
0 голосов
/ 21 февраля 2009

Если вы просто запускаете регулярное выражение для имени одного игрока за раз, я бы предложил:

/(\w+)\W+(\w+)$/

В английском это означает «хотя бы один символ слова, за которым следует хотя бы один символ, не состоящий из слов, за которым следует хотя бы один символ слова, а затем конец строки»

«Символ слова» - это буквы, цифры и подчеркивание. Так что, если люди когда-либо используют что-то кроме этих символов в своих тегах / никах, это нужно будет изменить. Например, если у людей также могут быть дефисы в никах, вам понадобится:

/(\w+)\W+([\w-]+)$/

Насколько я знаю, люди всегда используют знаки пунктуации (и / или пробелы) для разделения своего клана и своего никнейма, поэтому \ W + там должно быть хорошо.

Что касается случая, который вы дали без разделителя (clanplayer1, clanplayer2), то нет способа решить эту проблему, не посмотрев имена нескольких игроков, которые, как вы знаете, находятся в одном клане, и не выяснив, с какого момента их имена начинают отличаются, поэтому это не может быть решено с помощью одного регулярного выражения.

...