我有一个文本文件,结构如下:
KEYWORD0 DataKey01-DataValue01 DataKey02-DataValue02 ... DataKey0N-DataValue0N
KEYWORD1 DataKey11-DataValue11 DataKey12-DataValue12 DataKey13-DataValue13
_________DataKey14-DataValue14 DataKey1N-DataValue1N (1)
// It is significant that the additional datakeys are on a new line
(1)下划线不是数据的一部分。我用它来对齐数据。
问题:如何使用正则表达式将数据转换为此格式?
<KEYWORD0>
<DataKey00>DataValue00</DataKey00>
<DataKey01>DataValue01</DataKey01>
<DataKey02>DataValue02</DataKey02>
<DataKey0N>DataValue0N</DataKey0N>
</KEYWORD0>
<KEYWORD1>
<DataKey10>DataValue10</DataKey10>
<DataKey11>DataValue11</DataKey11>
<DataKey12>DataValue12</DataKey12>
<DataKey13>DataValue12</DataKey13>
<DataKey14>DataValue12</DataKey14>
<DataKey1N>DataValue1N</DataKey1N>
</KEYWORD1>
答案 0 :(得分:0)
^(\ w)的\ S *((\ w)的\ S *)(\ r \ n ^ \ S +(\ w)的\ S *)*
这开始进入附近但我认为这在编程语言中更容易做到...只是逐行处理文件...
答案 1 :(得分:0)
您需要在.NET中使用Regex的“组和匹配”功能,并应用以下内容:
([A-Z\d]+)(\s([A-Za-z\d]+)\-([A-Za-z\d]+))*
答案 2 :(得分:0)
如果DataValue和DataKey项不能包含<
或>
或' - '字符或空格,您可以执行以下操作:
使用与此类似的正则表达式以字符串形式读取文件并替换为replaceAll:([^- \t]+)-([^- \t]+)
并将其用作替换(<$1>$2</$1>
)。这会将这样的内容转换为DataKey01-DataValue01
,如下所示:<DataKey01>DataValue01</DataKey01>
。
之后,您需要运行另一个全局替换,但此正则表达式^([^ \t]+)(\s+(?:<[^>]+>[^<]+</[^>]+>[\s\n]*)+)
并再次替换为<$1>$2</$1>
。
这应该可以解决问题。
我不在VB.net中编程,所以我不知道实际语法是否正确(在某些情况下,您可能需要将\
加倍或翻两倍)。您应该确保为第二次传递启用Multiline选项。
解释:
([^- \t]+)-([^- \t]+)
[^- \t]+
)将匹配任何不包含
或-
或\t
的字符串。这标记为$ 1(注意它周围的括号)-
将与-
字符[^- \t]+
)将再次匹配任何不包含
或-
或\t
的字符串。这也标记为$ 2(注意它周围的括号)ab-cd
<ab>cd</ab>
字符串
在此步骤之后,文件如下所示:
KEYWORD0 <DataKey00>DataValue00</DataKey00> <DataKey01>DataValue01</DataKey01>
<DataKey02>DataValue02</DataKey02> <DataKey0N>DataValue0N</DataKey0N>
KEYWORD1 <DataKey10>DataValue10</DataKey10> <DataKey11>DataValue11</DataKey11>
<DataKey12>DataValue12</DataKey12> <DataKey13>DataValue12</DataKey13>
<DataKey14>DataValue12</DataKey14> <DataKey1N>DataValue1N</DataKey1N>
^([^ \t]+)(\s+(?:<[^>]+>[^<]+</[^>]+>[\s\n]*)+)
^([^ \t]+)
标记并匹配从该行开始的任何非
或\t
字符串(这是$1
)(
开始标记
\s+
空格(?:
非标记组从此处开始
<[^>]+>
匹配一个开放的xml标记:<ab>
[^<]+
匹配代码bc
</[^>]+>
匹配结束标记</ab>
[\s\n]*
一些可选的空格或换行符)+
关闭未标记的组并重复至少一次)
关闭标记(这是$2
)现在直接替换。
希望它有所帮助。
但如果这不是一次性工作,你应该尝试制作一个简单的解析器:)
答案 3 :(得分:0)
正则表达式是masochists,它是VB.NET中一个非常简单的文本解析器(从C#转换,所以检查错误):
Public Class MyFileConverter
Public Sub Parse(inputFilename As String, outputFilename As String)
Using reader As New StreamReader(inputFilename)
Using writer As New StreamWriter(outputFilename)
Parse(reader, writer)
End Using
End Using
End Sub
Public Sub Parse(reader As TextReader, writer As TextWriter)
Dim line As String
Dim state As Integer = 0
Dim xmlWriter As New XmlTextWriter(writer)
xmlWriter.WriteStartDocument()
xmlWriter.WriteStartElement("Keywords")
' Root element required for conformance
While (InlineAssignHelper(line, reader.ReadLine())) IsNot Nothing
If line.Length = 0 Then
If state > 0 Then
xmlWriter.WriteEndElement()
End If
state = 0
Continue While
End If
Dim parts As String() = line.Split(Function(c) [Char].IsWhiteSpace(c), StringSplitOptions.RemoveEmptyEntries)
Dim index As Integer = 0
If state = 0 Then
state = 1
xmlWriter.WriteStartElement(parts(System.Math.Max(System.Threading.Interlocked.Increment(index),index - 1)))
End If
While index < parts.Length
Dim keyvalue As String() = parts(index).Split("-"C)
xmlWriter.WriteStartElement(keyvalue(0))
xmlWriter.WriteString(keyvalue(1))
xmlWriter.WriteEndElement()
index += 1
End While
End While
If state > 0 Then
xmlWriter.WriteEndElement()
End If
xmlWriter.WriteEndElement()
xmlWriter.WriteEndDocument()
End Sub
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
请注意,我在XML中添加了一个根元素,因为.Net XML对象只是像读写符合XML一样。
另请注意,该代码使用extension I wrote for String.Split。