我正在尝试使用strsplit
和perl正则表达式在R中拆分字符串。该字符串由各个字母数字标记组成,以句点或连字符分隔,例如"WXYZ-AB-A4K7-01A-13B-J29Q-10"
。我想拆分字符串:
"01A"
生成["01", "A"]
(但是"012A"
,{ {1}},"B1A"
和"0A1"
未分割。)例如,"01A2"
应生成"WXYZ-AB-A4K7-01A-13B-J29Q-10"
。
我当前的正则表达式是["WXYZ", "AB", "01", "A", "13", "B", "J29Q", "10"]
,它在this online regex tester中完美运行。
此外,备选方案的两个部分((?<=[-.]\\d{2})(?=[A-Z][-.]))|[.-]
和((?<=[-.]\\d{2})(?=[A-Z][-.]))
,当它们单独使用时,都可以按照R中的预期分割字符串:
[.-]
但是当我尝试使用替代方法组合它们时,第二个正则表达式停止工作,并且字符串仅在句点和连字符上分开:
#correctly splits on periods and hyphens
strsplit("WXYZ-AB-A4K7-01A-13B-J29Q-10", "[.-]", perl=T)
[[1]]
[1] "WXYZ" "AB" "A4K7" "01A" "13B" "J29Q" "10"
#correctly splits tokens where a letter follows two digits
strsplit("WXYZ-AB-A4K7-01A-13B-J29Q-10", "((?<=[-.]\\d{2})(?=[A-Z][-.]))", perl=T)
[[1]]
[1] "WXYZ-AB-A4K7-01" "A-13" "B-J29Q-10"
为什么会这样?这是我的正则表达式或#only second alternative is used
strsplit("WXYZ-AB-A4K7-01A-13B-J29Q-10", "((?<=[-.]\\d{2})(?=[A-Z][-.]))|[.-]", perl=T)
[[1]]
[1] "WXYZ" "AB" "A4K7" "01A" "13B" "J29Q" "10"
的问题吗?我怎样才能达到理想的行为?
strsplit
答案 0 :(得分:2)
阻止您不必考虑onCreateView
算法如何工作的替代方法是使用原始正则表达式strsplit
在所有正确的位置插入一个简单的拆分字符,然后使用{ {1}}做直截了当的分裂。
gsub
当然,RichScriven的回答和WiktorStribiżew的评论可能更好,因为他们只有一个函数调用。
答案 1 :(得分:1)
您可以使用消费版本的正向前瞻(匹配重置运算符\K
)来确保strsplit
在R中正常工作,并避免使用在积极的一面内看消极的看法。
"(?<![^.-])\\d{2}\\K(?=[A-Z](?:[.-]|$))|[.-]"
请参阅R demo online(以及regex demo here)。
strsplit("XYZ-02-01C-33D-2285", "(?<![^.-])\\d{2}\\K(?=[A-Z](?:[.-]|$))|[.-]", perl=TRUE)
## => [[1]]
## [1] "XYZ" "02" "01" "C" "33" "D" "2285"
strsplit("WXYZ-AB-A4K7-01A-13B-J29Q-10", "(?<![^.-])\\d{2}\\K(?=[A-Z](?:[.-]|$))|[.-]", perl=TRUE)
## => [[1]]
## [1] "WXYZ" "AB" "A4K7" "01" "A" "13" "B" "J29Q" "10"
此处,模式匹配:
(?<![^.-])\d{2}\K(?=[A-Z](?:[.-]|$))
- 一系列:
(?<![^.-])\d{2}
- 2个数字(\d{2}
),前面没有.
和-
以外的字符(即前面有.
或-
或字符串的开头,这是避免在一个环境中进行交替的常见技巧)\K
- 匹配重置运算符,使正则表达式引擎丢弃到目前为止匹配的文本,并继续匹配后续子模式(如果有的话)|
- 或[.-]
- 匹配.
或-
。答案 2 :(得分:0)
感谢Rich Scriven和Jota,我能够解决问题。每次strsplit
找到匹配项时,它会在查找下一个匹配项之前删除匹配项及其左侧的所有内容。这意味着当外观与前一个匹配重叠时,依赖于后视的正则表达式可能无法按预期运行。在我的情况下,令牌之间的连字符在匹配时被删除,这意味着第二个正则表达式无法使用它们来检测令牌的开头:
#first match found
"WXYZ-AB-A4K7-01A-13B-J29Q-10"
^
#match + left removed
"AB-A4K7-01A-13B-J29Q-10"
#further matches found and removed
"01A-13B-J29Q-10"
#second regex fails to match because of missing hyphen in lookbehind:
#((?<=[-.]\\d{2})(?=[A-Z][-.]))
# ^^^^^^^^
"01A-13B-J29Q-10"
#algorithm continues
"13B-J29Q-10"
根据Jota的建议,通过替换[.-]
类以使用boundary anchor检测外观中令牌的边缘来解决此问题:
> strsplit("WXYZ-AB-A4K7-01A-13B-J29Q-10", "[-.]|(?<=\\b\\d{2})(?=[A-Z]\\b)", perl=T)
[[1]]
[1] "WXYZ" "AB" "A4K7" "01" "A" "13" "B" "J29Q" "10"