Viewed   67 times

I have this simple pattern that splits a text into periods:

$text = preg_split("/[.:!?]+/", $text);

But I want to include . : or ! at the end of the array items.

That is, now for "good:news.everyone!" I have:

array("good", "news", "everyone", "");

But I want:

array("good:", "news.", "everyone!", "");



Here you go:

preg_split('/([^.:!?]+[.:!?]+)/', 'good:news.everyone!', -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

How it works: The pattern actually turns everything into a delimiter. Then, to include these delimiters in the array, you can use the PREG_SPLIT_DELIM_CAPTURE constant. This will return an array like:

array (
    0 => '',
    1 => 'good:',
    2 => '',
    3 => 'news.',
    4 => '',
    5 => 'everyone!',
    6 => '',

To get rid of the empty values, use PREG_SPLIT_NO_EMPTY. To combine two or more of these constants, we use the bitwise | operator. The result:

array (
    0 => 'good:',
    1 => 'news.',
    2 => 'everyone!'
Saturday, September 24, 2022

You can use preg_split with the PREG_SPLIT_DELIM_CAPTURE option. The regular expressions is not quite as elegant as @Jan Turo?'s back reference approach because the required capture group messes up the results.

$str = "the 'cat "sat" on' the mat the "cat 'sat' on" the mat";
$match = preg_split("/('[^']*'|"[^"]*")/U", $str, null, PREG_SPLIT_DELIM_CAPTURE);
Wednesday, December 7, 2022

I don't think using pcre regex is necessary ... if it's really splitting words you need.

You could do something like this and benchmark see if it's faster / better ...

$splitby = array('these','are','the','words','to','split','by');
$text = 'This is the string which needs to be split by the above words.';

$split = explode(' ', $text);
$result = array();
$temp = array();

foreach ($split as $s) {

    if (in_array($s, $splitby)) {
        if (sizeof($temp) > 0) {
           $result[] = implode(' ', $temp);
           $temp = array();
    } else {
        $temp[] = $s;

if (sizeof($temp) > 0) {
    $result[] = implode(' ', $temp);


/* output

array(4) {
  string(7) "This is"
  string(18) "string which needs"
  string(2) "be"
  string(5) "above words."

The only difference with your output is the last word because "words." != "word" and it's not a split word.

Friday, December 16, 2022

The "Windows Script Host" framework (if ya want to call it that), offers an XML wrapper document that adds functionality over regular vbs files. One of which is the ability to include external script files of both the VBscript and Jscript flavors. I never got very deep into it, but I think it would do what you're wanting to do.

You can include JavaScript, VBScript, or modules of other WScript script languages.

Example WSF file:

<job id="IncludeExample">
   <script language="JavaScript" src="sprintf.js"/>
   <script language="VBScript" src="logging.vbs"/>
   <script language="VBScript" src="iis-queryScriptMaps.vbs"/>

If the above file is called "iis-scriptmaps.wsf", run it this way with cscript.exe:

cscript.exe  iis-scriptmaps.wsf
Sunday, August 14, 2022

One of my friends helped me solve this issue with the help of zx2c4 (Jason Donenfeld) from WireGuard. I am sharing our solution here for the next person with this same problem.

WireGuard for Windows added support for Table = off in v0.3.15. This makes it so WireGuard does not update the routing table when the tunnel is opened.

At this point we have a tunnel but windows will not route traffic through it even if it is the only adapter for the application. To solve this issue we need to add a default route to the adapter with a lower priority than our regular default route.

To do this we need to first enable DangerousScriptExecution in WireGuard. To do this we need to set the Registry Key HKEY_LOCAL_MACHINESoftwareWireGuardDangerousScriptExecution to DWORD(1) using regedit. The key does not exist by default and needs to be created using regedit. Then WireGuard needs to be restarted.

Once this is done we need to run some PowerShell commands when we start and stop the tunnel to create our default route for the tunnel. This route needs to have a higher metric/cost (lower priority) than our normal default route. For this solution we used a metric value of 95 (10 higher than the highest automatic metric).

WireGuard has the ability to automatically execute windows commands specified in the PreUp, PostUp, PreDown, and PostDown options in the tunnel config. We use this to set up our routes automatically.

WireGuard sets the environment variable WIREGUARD_TUNNEL_NAME to the name of this exact tunnel when it is running commands. We can convert it to a PowerShell object by calling $wgInterface = Get-NetAdapter -Name %WIREGUARD_TUNNEL_NAME%.

Once we have the tunnel as a PowerShell object we can set up or take down our route in windows.

To create our route we call route add mask IF $wgInterface.ifIndex metric 95

To remove our route we call route delete mask if $wgInterface.ifIndex metric 95

When we combine all of this together we end up with the following under [Interface] in the tunnel config. PostUp, PreDown, and Table = off are what this solution gives.

PrivateKey = <...>
Address = <...>
DNS = <...>
PostUp = powershell -command "$wgInterface = Get-NetAdapter -Name %WIREGUARD_TUNNEL_NAME%; route add mask IF $wgInterface.ifIndex metric 95"
PreDown = powershell -command "$wgInterface = Get-NetAdapter -Name %WIREGUARD_TUNNEL_NAME%; route delete mask if $wgInterface.ifIndex metric 95"
Table = off

PublicKey = <...>
AllowedIPs =,::0/0
Endpoint = <...>
Tuesday, November 1, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :