簡體   English   中英

在Perl中第n個字符的位置/索引處分割字符串(或正則表達式匹配項)?

[英]Split string (or regex match) at position/index of nth character in Perl?

有一個措辭類似的問題,但我認為這略有不同。

基本上,說我有這個字符串:

aa{bb{dccd

在這里,我想在最后一個括號{處分割字符串。 並將零件作為數組返回。 我可以使用rindex輕松找到此字符的位置(從0開始的索引):

perl -e '
$aa="aa{bb{dccd" ;
$ri = rindex($aa, "{") ;
print "$ri\n"; '

5

...而且鑒於我不是Perl編碼器,我想到的第一件事是使用類似$str = split($aa, 3) 不幸的是,這是不正確的語法split將正則表達式作為第一個參數(要匹配的內容),將字符串作為第二個參數-並且它不采用整數位置索引作為參數。

我發現了類似Perl Guru論壇的帖子:Perl編程幫助:中級:在字符數上拆分或拼接字符串? ,建議在類似的情況下使用substr 但是,按照上面的示例,我必須寫兩個substr來填充列表,所以我寧願聽到替代substr的信息。

基本上,如果可以將第N個字符的位置匹配問題表示為正則表達式匹配,則split也可以正常工作-所以這將是我的主要問題。 但是,我也想知道是否有Perl內置函數可以接受指定字符位置的整數列表/數組,並返回包含拆分部分的數組。

編輯:

綜上所述-我想擁有字符索引,因為我想將它們打印出來以進行調試; 同時使用它們將字符串拆分為數組-但不使用substr

EDIT2:我剛剛意識到我在OP中遺漏了一些東西-也就是說,在我正在解決的問題中,我必須首先檢索字符索引(通過rindex或其他方式); 然后我必須對它們進行計算(因此它們可能會增加或減少)-只有這樣,我才應該對字符串進行分割(基於新的索引值)。 可能是我的原始示例太簡單了,沒有太多地關注索引/字符位置( 更不用說我對split初衷仍然意味着字符索引-但是我真的不記得它使用哪種編程語言來自:)

my ($pre, $post) = split /\{(?!.*\{)/s, $s;

要么

my ($pre, $post) = $s =~ /^(.*)\{(.*)/s;

第二個可能更好。

如果您需要{的索引,請使用length($pre) (使用第二種解決方案,您還可以使用$-[2] - 1 。請參見perlvar中的 @-@+ 。)

你寫了:

我還想知道是否有Perl內置函數可以接受指定字符位置的整數列表/數組,並返回包含拆分部分的數組。

要創建一個使用偏移量列表並生成具有這些拆分位置的子字符串列表的函數,請將偏移量轉換為長度,並將其作為參數傳遞給unpack

Perl Cookbook的第1章中有一個&cut2fmt函數可以完成此任務。 這是摘錄,經作者的允許在此處轉載:

有時,您更喜歡將數據視為在特定列中被分割。 例如,您可能希望將剪切片段放置在位置8、14、20、26和30之前。這些是每個字段開始的列號。 盡管您可以計算出正確的unpack格式為"A7 A6 A6 A6 A4 A*" ,但是對於那些懶惰的Perl程序員來說,這太麻煩了。 讓Perl為您解決。 使用下面的cut2fmt函數:

sub cut2fmt {
      my(@positions) = @_;
      my $template   = '';
      my $lastpos    = 1;
      foreach $place (@positions) {
          $template .= "A" . ($place - $lastpos) . " ";
          $lastpos   = $place;
      }
      $template .= "A*";
      return $template;
  }

  $fmt = cut2fmt(8, 14, 20, 26, 30);
  print "$fmt\n";

  A7 A6 A6 A6 A4 A*

因此,您將使用以下方式:

$fmt = cut2fmt(8, 14, 20, 26, 30);
@list = unpack($fmt, $string);

或直接作為

@list = unpack(cut2fmt(8, 14, 20, 26, 30), $string);

我相信這就是您要的。

以下是一些方法:

split /.*\K{/, $str;
split /{(?!.*{)/, $str;
$str =~ /(.*){(.*)/;

如果字符串可以跨越多行,請使用/regex/s

使用rindex進行此操作的rindex是使用substr根據{的位置提取字符串的兩個部分。

請注意,這在后綴部分包括{ 要排除它,您可以在第二個substr調用中使用$i + 1

my $str = "aa{bb{dccd";

my $i = rindex $str, '{';
my $pref = substr $str, 0, $i;
my $suff = substr $str, $i;

print $pref, "\n";
print $suff, "\n";

輸出

aa{bb
{dccd

更新資料

我剛剛讀過有關您希望避免使用substr並在一次操作中進行拆分的願望。 像這樣unpack就能幫到您

my $str = "aa{bb{dccd";

my $i = rindex $str, '{';

my ($pref, $suff) = unpack "A$i A*", $str;

print $pref, "\n";
print $suff, "\n";

與先前的代碼具有相同的輸出。

我仍然看不出這有什么困難。 您是否不想舍棄括號(或任何分隔符)? @Qtax解決方案的這些改編使大括號保留在第一個或第二個子字符串中:

# split before the brace
split /.*\K(?=\{)/, $str;
split /(?=\{(?!.*\{))/, $str;
$str =~ /(.*)(\{.*)/;

# split after the brace
split /.*\{\K)/, $str;
split /(?<=\{(?!.*\{))/, $str;
$str =~ /(.*\{)(.*)/;

(我知道沒有必要逃避括號,但是我認為用這種方式閱讀起來要容易一些。)

是的,我將其作為答案發布,這是我取得的成就。

由於這些資源:

...我了解了“大括號”正則表達式運算符{n} ,它' 與前面的字符或字符范圍完全匹配n次 因此,我可以匹配/.{5}(.)/

perl -e '
$aa="aa{bb{dccd" ;
$aa =~ /.{5}(.)/  && print "--${1}--\n"; '

--{--

這將通過前5個“任意”字符進行選擇-然后選擇並打印下一個。 要么:

/               # start regex
 {              # match "{" character
  {5}           # repeat previous five times
     (.)        # select into match group (the $1) next character
        /       # end regex

因此,最后,我可以使用rindex進行這樣的拆分:

perl -e '
$aa="aa{bb{dccd" ;
$ri = rindex($aa, "{") ;
$aa =~ /.{$ri}(.)/  && print "--${1}--\n";
@res = split(/^.{$ri}(.)/, $aa);
print join("; ", @res) . "\n"; '

--{--
; {; dccd

..但鑒於這也需要在開始時進行一些捕獲,因此這里有其他變體:

@res = split(/^(.{$ri})(.)/, $aa);

--{--
; aa{bb; {; dccd


@res = split(/^(.{$ri})./, $aa);

--{--
; aa{bb; dccd

...兩者都對我有用-除了我有一個空白作為第一項內容,我想在一次通過中消除它(不調用多余的splice ,但是不知道如何:)

干杯!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM