LoginSignup
0
0

Powershell 正規表現 不定期に長い一致

Posted at

まず回答から

Using namespace system
Using namespace System.Text
Using namespace System.Text.RegularExpressions
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
$params = @{"q"="Powershell"}
$vbCrLf = "`r`n"
$strTest = @"
<div>
 <div>
  <div>
    <a href = "https://www.excite.co.jp">
  excite 1
  </a>
</div>
</div>
</div>
<div>
 <div>
  <div>
  <a href = "https://www.google.co.jp">
  gooogle 2
  </a>
</div>
</div>
</div>
<div>
 <div>
  <div>
    <a href = "https://www.yahoo.co.jp">
  yahoo 3
    </a>
    <a href = "https://www.yahoo.co.jp">
  Sub
    </a>
</div>
</div>
</div>
<div>
 <div>
  <div>
      <a href = "https://www.baidu.com">
  baidu 4
    </a>
</div>
</div>
</div>
<div>
 <div>
  <div>
      <a href = "https://www.naver.com">
  naver 5
    </a>
</div>
</div>
</div>
"@
$ret3 =[regex]::Matches($strTest, "^<div`>",'multiline');$ret3.Count; #"(.*)(.*)(.*)(.*)(\s*<`/a>\s*<`/div>\s*<`/div>\s*<`/div>)",'multiline');$ret3[0].Value ; $ret3.count
# Indexは0から始まるが、0はいらない。
for($i = 1 ; $i -lt $ret3.Count;$i++){
if($i -eq 1){
# 1文字目からしているすると食われるので、0から書く
$str11 = $strTest.Substring(0,  $ret3[1].Index)
}ElseIf($i -eq ($ret3.count -1 )  ){
$str11 = $strTest.Substring( $ret3[$i].Index, $strTest.Length -  $ret3.Item($i).index)
}Else{
$str11 = $strTest.Substring( $ret3.Item($i -1 ).Index, $ret3.Item($i).index - $ret3.Item($i -1 ).index )
}
write-host $i $str11
}

今回の並びの特徴

<div>が3つ続き</a></div></div></div>

というブロックになっているが、全く同じではない。

<div>
 <div>
  <div>
    <a href = "https://www.excite.co.jp">
  excite 1
  </a>
</div>
</div>
</div>
<div>
 <div>
  <div>
  <a href = "https://www.google.co.jp">
  gooogle 2
  </a>
</div>
</div>
</div>
<div>
 <div>
  <div>
    <a href = "https://www.yahoo.co.jp">
  yahoo 3
    </a>
    <a href = "https://www.yahoo.co.jp">
  Sub
    </a>
</div>
</div>
</div>
<div>
 <div>
  <div>
      <a href = "https://www.baidu.com">
  baidu 4
    </a>
</div>
</div>
</div>
<div>
 <div>
  <div>
      <a href = "https://www.naver.com">
  naver 5
    </a>
</div>
</div>
</div>

♯ はまった点

ブロックで抜くことはできない

現在ブロックで抜くことができない

"`<div>*\s*<`\a>\s*<`\div>\s*<`\div>\s*<`\div>`"
\

BingChatの貪欲

このパターンはどうか

"(<div>)(*)(\s*</a>([\s\S])*</div>\s*</div>\s*</div>)"

このパターンは、divタグの中にaタグがあるときに、divタグとaタグを閉じるためのものです。しかし、このパターンにはいくつかの問題があります。

()は、任意の文字を0回以上繰り返すことを意味しますが、これは貪欲な量指定子です。つまり、できるだけ多くの文字にマッチしようとします。そのため、divタグやaタグの属性に他のタグが含まれている場合には、正しくマッチしません。
(\s
)は、空白文字を0回以上繰り返すことを意味しますが、これも貪欲な量指定子です。つまり、できるだけ多くの空白文字にマッチしようとします。そのため、divタグやaタグの後に他のタグがある場合には、正しくマッチしません。
([\s\S]*)は、空白文字以外の任意の文字を0回以上繰り返すことを意味しますが、これも貪欲な量指定子です。つまり、できるだけ多くの文字にマッチしようとします。そのため、aタグの中に他のタグがある場合には、正しくマッチしません。
これらの問題を解決するためには、以下のようなパターンを使うことができます。

"(<div[>]*>)(<a[>]>)(.?)</a>(.?)</div>\s</div>\s*</div>"

[^>]は、>以外の任意の文字を意味します。これにより、divタグやaタグの属性に他のタグが含まれていてもマッチします。
?は、直前の量指定子を非貪欲にします。つまり、できるだけ少ない文字にマッチしようとします。これにより、divタグやaタグの後に他のタグがあってもマッチします。
.*?は、任意の文字を0回以上繰り返すことを意味しますが、非貪欲な量指定子です。つまり、できるだけ少ない文字にマッチしようとします。これにより、aタグの中に他のタグがあってもマッチします。

暫定結論

つまりBing Chatもケチをはつけられるが正解は得られない。
原因は長いから。

発想を変える

最初の<div>のみにマッチさせる。
そして、Indexを使う。
0....$ret[1].length.....$ret[2].length.....$ret[3].length.....$ret[k].length.....$ret[n-1].length.......文字列長
そうするとこのようになる
つまりインデックス1とインデックスn-1、それ以外
の3つに分けて文字列の起点、文字列の長さを設定して、SubStirngで抜く

その他

Indexの書き方

$i -1のときの配列のIndexの表記は角かっこではダメ
$ret[$i - 1] これはダメ
$ret.Item($i - 1) これはOK

Forは0からではない

Indexは0からつくが、forは1から始める。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0