3

我对复杂的正则表达式感到非常痛苦,但我希望朝着正确的方向轻推。当稍后使用全名时,我试图通过删除首字母来解析一些作者的姓名。我意识到可能不会有一个“完美”的解决方案来捕获所有异常,但我正在寻找一个“足够好”的解决方案。

示例输入

C S Clive Staples Lewis
T H Terence Hanbury White
R Salvatore
George R R Martin
J R R John Ronald Reuel Tolkien
J K Rowling

理想输出

Clive Staples Lewis
Terence Hanbury White
R Salvatore
George R R Martin
John Ronald Reuel Tolkien
J K Rowling

类似这样的东西:$str = preg_replace('#(?:\s+\S{1,2})+\s+#',' ',$str);虽然这显然缺少单个字符的第一个实例,但改变它会删除 r salvatore 中的 r 和 jk rowling 中的 jk。

感谢您的任何见解。

4

6 回答 6

2

你可以像这样使用它:

$str = 'C S Clive Staples Lewis';    
$str = preg_replace('#^([A-Z]\s)+(?=([A-Z]+\s+){2,})#i','',$str); 
echo $str; // Clive Staples Lewis

$str = 'J K Rowling';    
$str = preg_replace('#^([A-Z]\s)+(?=([A-Z]+\s+){2,})#i','',$str); 
echo $str; // J K Rowling
于 2013-10-11T13:28:41.870 回答
1

这似乎做了你所追求的:

var t = [
'C S Clive Staples Lewis'
,'T H Terence Hanbury White'
,'R Salvatore'
,'George R R Martin'
,'J R R John Ronald Reuel Tolkien'
,'J K Rowling'
];
for(var i=0,c=t.length;i<c;i++)
{
    var newStr = t[i].replace(/^([A-Z]) ([A-Z])((?: [A-Z])?) (\1\w+ \2\w+( \3\w+)?.+)$/,'$4');
    console.log(newStr);
}

/*
Results:

Clive Staples Lewis
Terence Hanbury White
R Salvatore
George R R Martin
John Ronald Reuel Tolkien
J K Rowling

*/

但是请注意,这种方法仅限于 3 个首字母(尽管我看不到你有更多的名字!)

从好的方面来说,这是检查首字母是否与以该字母开头的名称匹配,然后再删除它们

如果你需要 PHP:

$t = array(
'C S Clive Staples Lewis'
,'T H Terence Hanbury White'
,'R Salvatore'
,'George R R Martin'
,'J R R John Ronald Reuel Tolkien'
,'J K Rowling'
);
for($i=0,$c=count($t);$i<$c;$i++)
{
    $newStr = preg_replace('/^([A-Z]) ([A-Z])((?: [A-Z])?) (\1\w+ \2\w+( \3\w+)?.+)$/','$4',$t[$i]);
    var_dump($newStr);
}
于 2013-10-11T13:37:44.760 回答
1

您可以使用以下正则表达式:

^(?:([A-Z])(?=.*?\1[a-z]+)\s)+

它将匹配:

^ // from the beginning of the string
(?:  // non-capturing group
    ([A-Z]) // cature uppercase string
    (?=.*?\1[a-z]+) // positive lookahead for the letter captured above followed by multiple lowercase characters
    \s // followed by a space
)+ // multiple times

php 实时正则表达式示例

于 2013-10-11T14:04:28.613 回答
1

你可以使用这个:

$result = preg_replace('~^(?:[A-Z]\h){2,}~m', '', $str); 

如果你想放异常,你可以这样做:

$str = <<<LOD
C S Clive Staples Lewis
T H Terence Hanbury White
R Salvatore
George R R Martin
J R R John Ronald Reuel Tolkien
J K Rowling
J F Kennedy
C P E Bach
LOD;

$pattern = <<<'LOD'
~
  # definitions

  (?(DEFINE)
    (?<exceptions>  J \h K \h      Rowling
                  | J \h F \h      Kennedy
                  | C \h P \h E \h Bach
    )
  )

  # pattern

  ^(?!\g<exceptions>)
  (?:[A-Z]\h){2,}
~xm
LOD;

$result = preg_replace($pattern, '', $str);
于 2013-10-11T13:35:20.927 回答
0

即使您使用的是 PHP,您也没有指定语言。所以这是 Perl 中的一个示例。

use strict;
use warnings;

open my $data_fh, '<', 'Data1.txt' 
    or die "Can't open Data1.txt $!";

while (my $line = <$data_fh>) {
    $line =~ s/\b([A-Z])\b (?=.*?\b\1[A-Z]+\b)//xig; # Match an initial only if there is a word starting with that initial later in the string.
    $line =~ s/^\s*|\s*$//g; #strip leading or trailing space.
    print "$line\n";
}

#OUTPUT
Clive Staples Lewis
Terence Hanbury White
R Salvatore
George R R Martin
John Ronald Reuel Tolkien
J K Rowling
于 2013-10-11T13:50:08.323 回答
0

考虑以下正则表达式...

(?(^(\w\s)+\w{2,}(\s\w{2,}){1,})^(\w\s)+)

于 2013-10-11T13:44:24.290 回答