36

I've read the Emacs documentation for align-regexp but still have difficulty in understanding how it works. What I'm talking about is its prefixed form C-uM-xalign-regexp, not the simple form M-xalign-regexp. Here are my questions:

  • Does the first parameter (the regex) have to match the whole line of string? What if the regex only matchs a part of the string?
  • What to supply to the second parameter (Parenthesis group to modify (justify if negative))? As I understand here I need to supply a captured group number (count from 1), right? Does "justify if negative" means, if I want group 3 to right aligned, I'll supply -3 as the input?
  • What does the third parameter "amount of spacing (or column if negative)" mean? I just totally don't understand what this parameter does.

I've collect some text examples to practice. If anyone can use below text as examples that will be very helpful.


From

class CreateStudents < ActiveRecord::Migration
  def change
    create_table :students, :comment => "学生信息表" do |t|
      t.string :political_status, :comment => "政治面貌"
      t.string :education_level, :comment => "培养层次"
      t.string :enroll_method, :comment => "入学方式"
      t.date :enrolled_at, :comment => "入学时间"
      t.string :charge_type, :comment => "收费类别"
      t.string :enrolled_year, :comment => "学籍年度"
      t.string :enrolled_place, :comment => "生源所在地"
      t.string :bank_card_number, :comment => "银行卡号"
      t.string :bank_account_number,  :comment => "银行账号"
      t.boolean :is_active_duty, :default => false, :comment => "是否现役军人"
      t.boolean :is_equivalent_degree, :default => false, :comment => "是否同等学历"
      t.boolean :is_on_record, :default => true, :comment => "是否在籍"
      t.boolean :is_at_school, :default => true, :comment => "是否在校"
      t.timestamps
    end
  end
end

To

class CreateStudents < ActiveRecord::Migration
  def change
    create_table :students, :comment => "学生信息表" do |t|
      t.string  :political_status,     :comment => "政治面貌"
      t.string  :education_level,      :comment => "培养层次"
      t.string  :enroll_method,        :comment => "入学方式"
      t.date    :enrolled_at,          :comment => "入学时间"
      t.string  :charge_type,          :comment => "收费类别"
      t.string  :enrolled_year,        :comment => "学籍年度"
      t.string  :enrolled_place,       :comment => "生源所在地"
      t.string  :bank_card_number,     :comment => "银行卡号"
      t.string  :bank_account_number,  :comment => "银行账号"
      t.boolean :is_active_duty,       :default => false,  :comment => "是否现役军人"
      t.boolean :is_equivalent_degree, :default => false,  :comment => "是否同等学历"
      t.boolean :is_on_record,         :default => true,   :comment => "是否在籍"
      t.boolean :is_at_school,         :default => true,   :comment => "是否在校"
      t.timestamps
    end
  end
end

From

my @primes = (
    1,2,3,5,7,
    11,13,17,19,23,
    29,31,37,41,43,
);

To

my @primes = (
    1,  2,  3,  5,  7,
    11, 13, 17, 19, 23,
    29, 31, 37, 41, 43,
);

2 Answers 2

38

OK, first the alignments and then the explanation of how it works.

To align the first one, select the lines, do C-u M-x align-regexp and choose: \(\s-*\):, 1, 1, and y.

For the second, use ,\(\), 1, 1, and y.

How it works:

The regexp is tried on every line in the region. On each, if the lines are not aligned already, it will match on a different column. More specifically, the group you chose (the second parameter, “parenthesis group to modify”) will end on a different column on each line. The function will add spaces to the end of some of them and delete characters from others until all groups end at the same column, respecting the spacing constraints entered in the third parameter.

For example, taking some lines from the first case:

  t.string( ):enroll_method, :comment => "入学方式"
  t.date( ):enrolled_at, :comment => "入学时间"
  t.boolean( ):is_active_duty, :default => false, :comment => "是否现役军人"

The parenthesis ( ) represent the first group of the matching regexp. As you can see, on each line it ends on a different column. To align, the function will add one space to the one in the first line, three spaces to the one in the second line, and none in the third.

How many spaces it will add (or delete) is set by the third parameter, “amount of spacing”. This parameter really means, what the “natural” length of the parenthesis group should be. In the lines that don't need alignment, it will be exactly this length.

For example, on the second case, if you choose to align by regexp \(,\), spacing 1, you'll see that on the second and third lines no space is added, because the comma already provides a “spacing” of 1.

So, to recap:

  • regexp: match the place you are interested in aligning; to do it, one of its parenthesis groups will be extended with spaces, or shortened by deleting characters
  • parenthesis group: choose which one
  • spacing: if the group is shorter than this, spaces will be added to it; if it's longer, characters will be deleted from it, starting at the end (unless it's longer for the purposes of alignment, of course)
  • repeat: well, this is obvious, I think

The parameter variants (prepend minus sign):

  • justify: non-blank characters inside the group won't be deleted, and necessary spaces will be added/deleted from the left. On your second case, try: regexp \([0-9]+\), group -1.
  • column (instead of spacing): align to that fixed column (of course, it doesn't work well with “repeat”).
3
  • can you explain the regex \(\s-*\) ? The ( ) is a match group. \s the space special. but am confused by the -*. I though dash gives a range, and the * a multiplier...but [space] range multiplier doesn't make sense to me? thx.
    – ftravers
    Aug 3, 2021 at 14:37
  • @ftravers in Emacs-style regexps, "\s-" means a character of the "space" syntax class. See gnu.org/software/emacs/manual/html_node/emacs/…
    – angus
    Aug 4, 2021 at 19:16
  • For the second group, I selected the lines inside the parentheses, then did M-x align-regexp ,\(\) 1 1 y as suggested, and no realignment took place. Same for the second suggested pattern, that is, \(,\) 1 1 y. Did I not get it right, or...?
    – user19777
    Apr 28 at 18:22
4

Not a deep answer to the original question, but I wrote a bit of code in response to a different question that shows how to make multiple columns out of a single column:

https://emacs.stackexchange.com/a/22427/5137

It may contribute to understanding how the parameters work by demonstrating their use in code.

3
  • Please post/explain the code here; link-only answers can be problematic if the link goes dead. If you would rather leave it link-only, please convert the answer to a comment.
    – Dan
    May 28, 2016 at 9:16
  • 1
    Well it's a link to another emacs.stackexchange answer -- if that goes dead, you won't be seeing this answer either! (I do agree that this answer seems more like a comment, however).
    – phils
    May 28, 2016 at 9:55
  • 3
    I'm happy to post it as a comment, answer, chunk of code, or whatever you guys prefer (even deleting it wouldn't bother me). I was just trying to help, and it's hard for a newbie like myself to figure out the minimally disturbing protocol paths (although I do try -- it seemed to me that my "answer" was more of an alternative viewpoint to an answer than a comment on the postings by others, which is why I posted it the way I did. Ditto for explaining the link by posting my code vs just posting the link. I figured the link fit my minor answer better than a code answer.) Best regards Kevin
    – Kevin
    May 28, 2016 at 17:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.