「正規表現」または「Jいだけ」
この記事を書くきっかけとなった理由の説明から始めます。 少し前に発行された、habrを読んだ正規表現に関する記事は、私を感動させました。おそらく既に見ました。私は正直にこの記事を好まなかったのです。彼らはそれを書いたので、600ページ以上の本を使用して購入するという複雑な例を挙げました、それは私には思えますが、それらを使用できる人々を怖がらせるだけです。
私は特にマニュアルを調べませんし、私自身が覚えていない情報をあなたに詰め込みます。興味を持ち、それを使い始めるには、私が自分自身で使えるようにするのに十分であると確信しています。
WindowsとLinuxの両方に対応する「grep」を使用して、すべての例を挙げます(もちろん、彼にとってはもっと大切です)。
私自身はLinuxの下に座っているので、Linux自体を使用した例を示します。場合によっては「|」を使用します (「パイプ」)、出力リダイレクトコマンドですが、必要に応じて、一時的な結果ファイルを使用して実行することもできます。 したがって、正規表現の構文標準を使用します。したがって、正規表現が完全にサポートされているすべての場所で機能するはずです。
grepについて何も知らない人にアピールします。 使い慣れていないツールを使用しているので、混乱しないでください。例としてのみ使用されています。正規表現には、多くのテキストエディタでサポートされている標準化された構文があります。
種のために。 通常の検索が機能しなくなったときにファイルから単語やフレーズを選択する必要がある場合、短いパーサーを書く必要がありましたか?..
1.次の内容のログインを含むテキストファイルがあるとします。
.....
login="Figaro"
.....
login="Tolik"
........
ログインのリストを正確に取得する必要がありますが、この場合、ユーザーはどうすればよいですか?ファイルの重量が大きい場合は... MBまたはGBですか? またはそのようなタスクに直面する必要はありませんでしたか?..これを行う方法を学習します。
2.次に、タスクはこれです。「C ++」を使用したプロジェクトのソースコードがあり、このプロジェクトに含まれるクラス(便宜上、テンプレートクラスは省略します)と構造を調べる必要があります。
クラスと構造を次のように宣言できることを考えると(もちろん、アポストロフィは使用しません):
'class Foo'
'class Bar'
' class Any'
' struct A'
これも私たちがやることを学びます。
3.それで、まだ、いくつかのフォーマットファイルがあります。
user="Login" Passwd="anypassword"
各行に必要です
このファイルから見つける
3.1パスワードが数字のみで構成されているユーザー、
3.2パスワードが小文字のみで構成されるユーザー、
3.3大文字のみ
3.4文字が5文字より短く、小文字または大文字のみで構成されているもの。
ログインがIPアドレスに似ている3.5 、これらはボットのような非常に奇妙なユーザーです:))
(例:243.11.22.03または243-11-22-03または243_11_22_03)
すでに正規表現に精通している人は、ウォーミングアップのためにこれらの問題を解決し、結果を下にあるものと比較できます。
今のところこれで十分だと思います。
さて、残念ながら正規表現の文法はそれなしではできませんが、短いリストから始めましょう。説明を自分で書きます。したがって、正規表現とは大きく異なります。
記号 :
。 -ドットこれは任意の文字です。 文字、数字、記号があることがわからない場合は、ピリオドを書きます
\ w-これはいくつかの文字の単語です。残念ながら、そのような記号の付いたロシア文字をサポートする人はほとんどいません。たとえば、KDevelop 3.5.10は
\ d-これは数字です
\ s-これはスペースまたはタブ、つまりスペースです
\ l-grepの私のバージョンでは小文字の小文字はサポートされていません
\ u-grepの私のバージョンでは大文字はサポートされていません
[abcde]-リスト内の文字のいずれかがセットに含まれている
^-行の始まりをマーク
$-行末指定
()-括弧は式をグループ化するために使用されます
繰り返し :
括弧なしで「(式)(繰り返し)」として使用すると、以下でより明確になります。
*-式は0から始まる任意の回数繰り返すことができます。つまり、省略できます。
+-式は1回以上繰り返すことができます。つまり、存在する必要があります。
{3,6}は、この場合3〜6回の繰り返しを指定する普遍的な方法です
{3、} 3回以上の繰り返しから
? -式は0回または1回繰り返すことができ、{0,1}と書くことができます。
正規表現がない場合にのみ正規表現でエスケープする必要のある文字
\?、
\ +、
\ |、
\(、
\)
\。
\ [
\]
\-
\〜
実際、正規表現の構文は優れていますが、これが主なものですが、それでも一般的な開発では、より簡潔で理解しにくい表現を書くために他の機能に慣れることができます:))
grepについて少し説明します。これはコマンドラインからパラメーターを取得するコンソールユーティリティです。このツールにはGUIバージョンがあり、キーがあります。
-Pは、式が正規であると言います
-o文字列全体ではなく、見つかった正規表現のみを出力します
-rサブディレクトリで再帰的に下降します
*すべてのファイルを処理します(インクルードがない限り)
--include "* .h"は、拡張子が.hのファイルのみを使用します
言葉から行為に移りましょう。
タスク1
したがって、問題を解決し始めます。最初の条件を思い出してください。 logins.txt :
.....
login="Figaro"
.....
login="Tolik"
........
チェックしたlogins.txtファイルのテキスト:
.....
login="Figaro"
.....
login="Tolik" login="Petya"
ファイル:
探している式の例があります。
name="Figaro"
変化する部分を選択します。これは直接引用された単語です。構文を見て、使用される文字は「\ w」で、繰り返し回数は「+」です。すべてのペアを見つけるには、次の形式の式を取得します。
name="\w+"
つまり、logins.txtファイルがある場合、name = "login"のリストを受け取るコマンドは次のようになります。
grep -Po 'login="\w+"' logins.txt
しかし、条件では、ペアではなくログインのリストを取得する必要があり、そこからログインのみを抽出するためにname = "login"のような式を見てください。明らかに、引用符で式を取得する必要があり、正規表現は私たちが持っているものの一部のようになりますすでに:
"\w+"
結果からログインのリストを取得するために、次の構造を取得します
grep -Po 'login="\w+"' logins.txt | grep -Po '"\w+"'
(または、「|」の代わりに中間ファイルを使用して、このファイルに2番目のコマンドを適用します)
コマンドの出力:
最初のタスクは完了しました。ログインのリストを取得します。必要に応じて引用符を削除できますが、これは自分のものです。
チャレンジ番号2
、私は条件を思い出す: "" ( ) , - ( ) :
'class Foo'
'class Bar'
' class Any'
' struct A'
-チェックしたclass.hファイルのテキスト:
class Foo
class Bar
class Any
struct A
-ファイルの内容:
したがって、クラスヘッダーが行の先頭にあると想定しますが、それ以外の場合は非常に怪しいです。 広告行の例をご覧ください。
' class Any'
そして、この式を、一般化する他のすべての宣言に適したテンプレートに変えてみてください。
行の始まり=> '^'、
次に、スペースまたはタブ=> '\ s'が来ます。多分または多分== '*'ではありません。
単語class => class、または=> '|'が来ます word struct => struct、
スペースがあります=> '\ s'、少なくとも1つの=> '+'、
名前は=> '\ w'で、少なくとも1つの文字を含める必要があります=> '+'
構築のロジックは、結果として得られる式自体よりも複雑に見えます。
^\s*(class|struct)\s+\w+
そして、広告を見つけるチーム:
grep -Pr "^\s*(class|struct)\s+\w+" class.h
出力結果:
または、すべてのファイルに適用するアスタリスク:
grep -Pr "^\s*(class|struct)\s+\w+" *
完了、2番目のタスクが整理されました。
チャレンジ番号3
状態:3) , , user="Login" Passwd="anypassword" ,
3.1 ,
3.2 ,
3.3 ,
3.4 5 .
3.5 ip , :))
( 243.11.22.03 243-11-22-03 243_11_22_03 )
-チェックしたusers.txtファイルのテキスト:
user="Login" Passwd="12login"
user="Anya" Passwd="12341234"
user="Masha" Passwd="2345234524"
user="Pasha" Passwd="4657467"
user="234.255.252.21" Passwd="2342346354"
user="Petya" Passwd="0099"
user="Misha" Passwd="victor"
user="Lena" Passwd="VASYA"
user="Sveta" Passwd="PUPKIN"
user="Ira" Passwd="PETR"
user="Lera" Passwd="%^&&@&&@*****"
user="Sasha" Passwd=")(#@*)($#K$@LKJLKJLK"
user="Dima" Passwd="K:LSDKL:FS:LFD"
user="Serega" Passwd=")(*#@$(*#@()$"
user="212_2_3_3" Passwd="JDK"
user="225-234-234-22" Passwd="123"
user="192.116.166.13" Passwd="466"
user="234.255.252.22" Passwd="111"
-ファイル:
3.1数字のみのパスワードを見つけるには、引用符で囲まれた条件を満たせば十分です。
パスワードの値は単なる数字であり、非常に単純です。スケジュールを設定しなくてもすべてを理解できると思います。
user="[\w\d\._\-]+"\s+Passwd="\d+"
grep -P 'user="[\w\d\._\-]+"\s+Passwd="\d+"' users.txt
[\ w \ d \ ._ \-]-これらは有効な文字、数字、ピリオド、アンダースコア、ログインのダッシュです。
結果:
3.2小文字の指定に関する文法規則を見てみましょう。同様の条件があります。数字の代わりに小文字があり、その結果が得られます。
user="[\w\d\._\-]+"\s+Passwd="[az]+"
grep -P 'user="[\w\d\._\-]+"\s+Passwd="[az]+"' users.txt
結果:
3.3ここでは似ています:
user="[\w\d\._\-]+"\s+Passwd="[AZ]+"
grep -P 'user="[\w\d\._\-]+"\s+Passwd="[AZ]+"' users.txt
結果:
3.4ここで少し考えて、クラスまたは構造体を探していたときの同様のケースを思い出すことができます。長さの制限のみが追加されます。
しばらく立ち止まって自分で書くことをお勧めします:))。 真剣に、もう一度3.4項と問題2の解決策を読み、自分で式を書いてください。 試してから戻ってください。 =))
ここではそれほど複雑ではありません。
user="[\w\d\._\-]+"\s+Passwd="([az]|[AZ]){1,4}"
grep -P 'user="[\w\d\._\-]+"\s+Passwd="([az]|[AZ]){1,4}"' users.txt
結果:
3.5ここでは、式自体を記述し、その分析、つまり理解を自分で行いますが、もちろん、自分で表現することもできます。
私はそれを行います、段落3.5の解決策を自分で書くことを提案し、それをテストデータでチェックすることを提案する強さを感じている人、自分で書きたくない人のために、下の表現を圧倒するために残っています、私はあなたに署名する場合のみ怖いようです何も延期されません。
ここに式自体があります:
user="(\d{1,3}[\._\-]){3}\d{1,3}"\s+Passwd=".*"
grep -P 'user="(\d{1,3}[\._\-]){3}\d{1,3}"\s+Passwd=".*"' users.txt
ヒントをあげます:
ブロックが強調表示されます-(\ d {1,3} [\ ._ \-])これは、たとえば「251」です。 繰り返される
3回後、「251.243.243」のようなものが得られます。 その後に別の数字\ d {1,3}が続きます。
結果:
最後に、セットの名前を明示的に示すことができるため、\ dの代わりに[1234567890]または[0-9]を記述してロシア語の文字を明示的に示すことができますが、[aaaaaaaaaa]も指定できます。正しく理解されます。 小さい英字のみ[az]大きいのみ[AZ]小さい大きいおよび数字[a-zA-Z0-9]など。
あなたの注意をありがとう、私はアドバイスしたい-それを理解するために少し時間を費やして、それは本当に人生(特にプログラマー)を容易にします。