|
Использование регулярных выражений на примере VB.NET.
Основные принципы
1. Регулярные выражения ищут текст, совпадающий с определенным
шаблоном.
2. Регулярные выражения работают на уровне совпадений отдельных
символов.
Для пояснения этих принципов рассмотрим следующий пример:
Необходимо выделить из строки некоторого оператора SQL SELECT FROM
название полей и их описание. Проанализировав синтаксис оператора Select,
приходим к выводу, что нужно выделить часть строки, идущую перед FROM, а затем
постараться выделить названия полей и их описание. Допустим,что
в этом операторе используется для описания полей(если
они есть) ключевое слово AS. Кроме того могут использоваться квадратные скобки
для обрамления описания и стандарные функции для получения полей
оператора SELECT. Например SELECT ROUND(first,3) as [quantity of word,
million], ROUND(second,3)as[quantity of errors, billion]FROM(mytable). Таким
образом, задача усложняется наличаем квадратных и круглых скобок, которые могут
в свою очередь, содержать запятые. Нужно выражение, выделяющее
запятые, не входящие в незакрытую круглую или квадратную
скобку. В документации о регулярных выражениях в .NET описывается
группа (?! ) с непереводимым названием "Zero-width positive lookahead
assertion". Которая вроде может указывать на группу, которая не должна
предшествовать искомому выражению. После небольших но тяжелых мучений с
негативной логикой, пытаемся перейти в позитивную и искать, наоборот запятые,
которые входят в такие скобки и их потом не учитывать. Наверное, это может в
конечном счете привести к цели, но на мой взгляд цель в данном случае не
оправдывает средств. В конечном счете приходим к следующему компромиссу
между программной логикой и использованием регулярных выражений (Строка, передаваемая в данном примере в функцию не содержит
ведущего ключевого слова SELECT - по условиям задачи его не было):
Function ParseStrSelect(ByVal str As String) As IList
Dim errors As String
errors = "ok"
Dim strbeg As String
Dim strend As String
Dim pos As Integer
Dim fields As New System.Collections.ArrayList
Dim pat As String = "[\s\[\)](from)[\s\(\[]"
' Compile the regular expression.
Dim r As Regex = New Regex(pat, RegexOptions.IgnoreCase)
Dim match As Match
match = r.Match(str)
Dim mystr As String() '= r.Split(str)
strbeg = str.Substring(0, match.Index + 1)
strend = str.Substring(match.Index + match.Length - 1)
Dim azp As Integer, akr As Integer, akv As Integer
pos = 0
Do
azp = strbeg.IndexOf(",", pos)
akr = strbeg.IndexOf("(", pos)
akv = strbeg.IndexOf("[", pos)
Select Case firsrtchar(azp, akr, akv)
Case -1
fields.Add(strbeg.Substring(0))
Exit Do
Case 1
fields.Add(strbeg.Substring(0, azp))
strbeg = strbeg.Substring(azp + 1)
pos = 0
Case 2 ' "(" found
pos = akr
pos = strbeg.IndexOf(")",pos)
If pos = -1 Then
errors = "( don't match"
Exit Do
End If
Case 3
pos = akv
pos = strbeg.IndexOf("]",pos)
If pos = -1 Then
errors = "[ don't match"
Exit Do
End If
End Select
Loop
If errors = "ok" Then
Return fields
Else
Return Nothing
End If
End Function
'return 1 - , 2 - ) 3 - [ -1 - not found ,
Function firsrtchar(ByVal zp As Integer, ByVal kr As Integer, ByVal kv As Integer)
If zp = -1 Then Return -1
If kr = -1 Then kr = 10000
If kv = -1 Then kv = 10000
If zp < kr And zp < kv Then Return 1
If kr < zp And kr < kv Then Return 2
If kv < zp And kv < kr Then Return 3
End Function
Программу можно использовать следующим образом:
ParseStrSelect("ROUND(first,3) as [quantity of word, million],
ROUND(second,3)as[quantity of errors, billion]FROM(mytable)" )
Часть программы, заполняющая список lstFields полями
и из описаниями из строк полученного массива fields приведена ниже:
Function mytrim(ByVal str As String) As String
Dim mystr As String
mystr = str.Trim()
If mystr.StartsWith("[") Then
mystr = mystr.TrimStart("[")
mystr = mystr.TrimEnd("]")
End If
Return mystr
End Function
Sub ParseField(ByVal str As String)
Dim field As String
Dim descr As String
Dim pat As String = "[\s\[\)](as)[\s\(\[]"
Dim r As Regex = New Regex(pat, RegexOptions.IgnoreCase)
Dim match As Match
match = r.Match(str)
Dim fielditem As New ListItem
If match.Success Then
field = str.Substring(0, match.Index + 1)
descr = str.Substring(match.Index + match.Length - 1)
Else
field = str
descr = str
End If
fielditem.Value = field
fielditem.Text = mytrim(descr)
lstFields.Items.Add(fielditem)
End Sub
То есть сложность использования в данном случае регулярных
выражений была вызвана тем, что вместо поиска определенного символьного
выражения была сделана попытка выделения логически связанной конструкции.
Алексей Шечков, 2005.
|
|
|